界面框架:



我采用了flex布局,先分左右,然后右侧再分上下。

步骤:

1. 首先实现简单的菜单

1.1 菜单是个菜单项数组 []

1.2 菜单项结构 例子

{
id:'001',
name: '历史轨迹', // 菜单名称
isTitle: true, // 表示可以展开
level: 1, // level控制缩进,vue动态class使用
expand: true, // 展开状态,
icon: require('@/assets/svg/track.svg'),
children:[ // 根据需要配置
{
id:'002',
name: '人员轨迹',
isTitle: false, // false表示是子节点,点击访问,而不是展开
level: 2, //
icon: require('@/assets/svg/person.svg'),
route:{
name:'historyTrack' // 这个name要和路由中配置的name保持一致,这个很关键
}
}
]
}

1.3 新建一个菜单,就叫 TreeMenu

下面代码就是TreeView菜单组件,里面递归了自己

<template>
<ul>
<li v-for="item in menu" :key="item.id">
<div :class='[item.isTitle? "menu-title": "menu-item", "level"+ item.level]' @click="toggleMenu(item)
<img v-show="item.icon" :src="item.icon" />
<span>{{item.name}}</span>
</div>
<TreeMenu v-if="item.children && item.expand" :menu="item.children" />
</li>
</ul>
</template>
  • "level-"+ item.level: 这是我设计的样式缩进level-1到level-5, panding-left每次增加12px
  • TreeMenu 递归调用自己绘制形成多级菜单
  • TreeMenu 有一个props,传递的数据结构就是 上面1.2定义的菜单项结构
  • li标签里的div中添加click事件 toggleMenu,负责处理是新打开一个菜单项对应的路由还是展开菜单,如:
toggleMenu(item){
const isTitle = item.isTitle
if(isTitle){ // 展开 or 折叠
this.$emit('expand', item) // 把该数据传给父组件,因为菜单数据是props从父组件传过来的,子组件修改会有警告,所以传事件给父组件,让父组件修改
}else{ // 打开菜单页面
if(this.$router.currentRoute.name !== item.route.name){ // 这个是为了防止点击已打开的页面,导致route模块告警说打开同一路由
this.$route.replace(item.route.name)
}
}
}

2. 然后实现AppMain:就是上面界面框架的内容部分

2.1 主要是<router-view></router-view>来展现菜单对应的路由里组件的内容

```HTML
<template>
<section>
<keep-alive :max="10" :include="cacheRoute">
<router-view :key="key" />
</keep-alive>
</section>
</template> <script>
// 省略乱七八糟的 ...
conputed:{
cacheRoute(){
const route = this.$store.getters['history/cacheRoute'] // 这个是Store中保存的已打开的路由,下面介绍,是个路由数组
return route.map(e=>e.name)
},
key(){
return this.$route.path
}
}
</script>
```
  • keep-alive 表示保活,就是你在打开其他组件的时候,当前组件不会销毁,下次打开不经历beforecreate、created、...、mounted等生命周期,从vue-devtools中也可以看到,他依然挂在AppMain下面,但是它是灰色的。注意:需要保活的组件vue配置的name属性必须配置且唯一。 详细信息见:keep-alive 官方文档
  • keep-alive的:max="10 表示最多保活十个组件,第十一个进来,第一个则移除,不再保活,防止占用系统过多资源,根据实际需要调整该数
  • keep-alive的:include="cacheRoute" 表示保活的组件包括这些。如果想让某个组件销毁,不再保活,则将组件对应的路由名称从cacheRoute中移除即可
  • router-view 个人理解就是用来展示当前路由对应组件的内容。 对这个理解不是太深,看了文档,模模糊糊的。详细信息见:router-view 官方文档
  • router-view的:key="key" 是打开的路由路径

3. 所打开页面的tag

<template>
<!-- 这个是上面的一长条,就是界面框架右上方的空间 -->
<div>
<!-- 这个就是一个个小的tag标签 -->
<route-link v-for="item in cacheRoute" :ref="item.path" :key="item.path" :to="{path:item.path, fullPath:item.fullPath}" custom :class="{'active-tab':activeRoute === item.name}" @click.middle.native="closeTab(item)">
<div>
{{item.meta.title}} <!-- 路由配置的标题 -->
<i class="close-btn" v-if="item.meta.closable!== false" @click.prevent="closeTab(item)" /> <!-- 关闭按钮,根据路由中配置的属性来决定是否显示关闭按钮从而操作该tag是否可以关闭,路由相关的数据结构下面贴出来 -->
</div>
</route-link>
</div>
</template>
  • route-link:它组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的<a>标签,可以通过配置 tag 属性生成别的标签(高版本中会抛出警告,说不再支持这个属性,请使用custom)。详细信息见:router-link 官方文档
  • <route-link v-for="item in cacheRoute":cacheRoute中保存的是在keep-alive保活的组件路由,使用store(VueX)管理
  • closeTab 方法可以将当前tag所代表的路由,从cacheRoute中移除,然后触发keep-alive的includes所绑定的数据,从keep-alive中移除,移除后会自动执行生命周期的destroyed 钩子进行销毁

4. 路由数据结构

4.1 例子

{
path:'/home',
name:'home', // 这个name要和1-2的菜单配置里route{name}一致
meta:{
title: '历史主页', // router-link 显示的tag标题
closable: false, // 这个是是否可以关闭
},
component:()=>import('@/views/home/home.vue'),
}
  • name: 1-2的菜单配置里route{name} 要和它一致
  • meta:它可以根据自己需要填充属性,title为 tag显示内容,closable是是否可以关闭

5. Store(VueX)

5.1 相关Store(VueX)的数据结构

{
cacheRoute: Array<Route>, // 实现:添加、删除(在组件被挂载、销毁的时候操作)
activeRoute: string,// 在挂载的时候操作,主要是为了修改css,高亮当前选择的菜单项和tag
}

6. mixin

6.1 mixin 内容

export default({
created(){
const cacheRoute = this.$route.getters['history/cacheRoute'] // 5.1 中的 cacheRoute,是个路由对象数组
if(cacheRoute.length === 0){ // 如果有路由是不可被关闭的,那么他将一直存在cacheRoute中,如果不在,那么就添加进去
// 找到不可关闭的路由,这里似乎可以通过route的mata属性配置的closable进行判定,我这样是写死的,固定住了
const route=this.$router.getRoutes().find(e=>e.name == "home")
this.$store.commit('history/addCacheRoute', route) // 添加进cacheRoute,这样就能显示在tag里面了
}
this.$store.commit('history/addCacheRoute', this.$route.currentRoute) // 将当前的路由加入 cacheRoute
this.$store.commit('history/setActiveRoute', this.$route.currentRoute.name)// 将当前路由设为活动的,便于高亮tag和菜单项
},
actived(){ // 这个生命周期的钩子是keep-alive的,激活当前组件时触发,还有个deactivated,取消激活当前组件时触发
this.$store.commit('history/setActiveRoute', this.$route.currentRoute.name)// 将当前路由设为活动的,便于高亮tag和菜单项
}
})

注意:该mixin需要在组件中混入

7. 界面组件层级

8. 依照7中图片结构实现思路

8.1 先设计路由,计算菜单有哪些,在Vue项目Router中设计好路由信息

8.2 HistoryHome组件中放入左上下模块:SideView、TagView、AppMain三个模块:菜单、标签栏、显示内容区域

8.3 在SideView中对着设计好的路由构造menu数据,对vue的Router理解比较深者可以根据路由来生成menu数据,我们项目需要自己手动构造menu数据。然后把构造好的menu数据给TreeView组件,使其生成菜单项,并绑定点击事件。在点击事件中,处理点击对象是展开/折叠或者路由跳转打开新页面。

8.4 新页面混入上面写的minxin,在created生命周期中将自身的路由对象存入Store的cacheRoute,方便TagView组件遍历展示。同时,将自身的name存入Store的activeRoute,便于SideView和TagView高亮。

8.5 TagView利用router-link,来实现组件跳转。遍历Store的cacheRoute,填充route-link所需要的属性,添加关闭按钮,实现关闭tag方法。在关闭tag方法中,只需要将tag对应的route从cacheRoute移除即可。router-link的tag属性不能用了,我使用css控制样式。

8.6 AppMain组件利用keep-alive 进行组件保活,即发生路由跳转,但是页面不执行销毁操作。使用router-view显示当前路由对应的组件内容。采用computed计算属性获取cacheRoute中存放的路由name属性,形成数组给keep-alive,这样在 打开新页面/需要关闭页面 时,双向绑定会触发,keep-alive会自动保活/取消保活组件,与操作联动起来。然后在router-view中将当前路由的path给出即可。

ruoyi-vue 界面框架构造的更多相关文章

  1. [虾扯蛋] android界面框架-Window

    从纯sdk及framwork的角度看,android中界面框架相关的类型有:Window,WindowManager,View等.下面就以这几个类为出发点来概览下安卓开发的"界面架构&quo ...

  2. iOS开发之旅:实现一个APP界面框架

    在上一篇博客中,给大家介绍了一下我们传统的 APP 界面框架-标签导航的一些优缺点,在这篇文章中我会来给大家演示,如何用代码去实现这一框架.本次的实现我会分成俩部分来讲,好了闲话少说,接下来进入到开发 ...

  3. 分享非常漂亮的WPF界面框架源码及插件化实现原理

      在上文<分享一个非常漂亮的WPF界面框架>中我简单的介绍了一个界面框架,有朋友已经指出了,这个界面框架是基于ModernUI来实现的,在该文我将分享所有的源码,并详细描述如何基于Mod ...

  4. 使用Vue+JFinal框架搭建前后端分离系统

    前后端分离作为Web开发的一种方式,现在应用越来越广泛.前端一般比较流行Vue.js框架,后端框架比较多,网上有很多Vue+SpringMVC前后端分离的demo,但是Vue+JFinal框架貌似没有 ...

  5. .Net/.Net Core 的界面框架 NanUI 发布新版本啦!

    发布前感悟 NanUI 自从上一次更新 NanUI 0.7 已经过去大半年,B站和头条的教学视频也只制作到了第二集. 有朋友悄悄问我是不是发生什么事故我删库跑路了所以那么长时间不更新项目不发布教程,当 ...

  6. 【Windows编程】系列第十一篇:多文档界面框架

    前面我们所举的例子中都是单文档界面框架,也就是说这个窗口里面的客户区就是一个文档界面,可以编写程序在里面输入或者绘制文本和图形输出,但是不能有出现多个文档的情况.比如下面的UltraEdit就是一个典 ...

  7. 【源码分享】WPF漂亮界面框架实现原理分析及源码分享

    1 源码下载 2 OSGi.NET插件应用架构概述 3 漂亮界面框架原理概述 4 漂亮界面框架实现  4.1 主程序  4.2 主程序与插件的通讯   4.2.1 主程序获取插件注册的服务   4.2 ...

  8. 分享一个漂亮WPF界面框架创作过程及其源码

    本文会作为一个系列,分为以下部分来介绍: (1)见识一下这个界面框架: (2)界面框架如何进行开发: (3)辅助开发支持:Demo.模板.VsPackage制作. 框架源码如下所示. 本文介绍第(1) ...

  9. 分享一个漂亮的ASP.NET MVC界面框架

    本文分享一个插件化的界面框架,该框架提供了用户.角色.权限管理功能,也提供了插件的管理和插件中心.下图是该界面框架的样式(全部源码和原理介绍下一篇分享,推荐越多,源码放的越早,呵呵). 要使用该界面框 ...

  10. Onsen UI – 新鲜出炉的 PhoneGap 界面框架

    Onsen UI 是一个基于元素自定义的 HTML5 UI 框架,用于构建你的移动前端.这个一个基于 Web 组件的概念的框架,让构建应用程序变得更加轻松.Onsen UI 专门针对 PhoneGap ...

随机推荐

  1. 揭秘“山姆黄牛”背后的技术逻辑:用Java实现会员管理系统的防黄牛策略

    在浙江绍兴的山姆超市外,"黄牛"现象引发了广泛关注.这些"黄牛"通过提供带入和结账服务,让未办理会员卡的消费者也能进入超市购物.这一行为不仅扰乱了市场秩序,也对 ...

  2. git 本地项目与远程地址建立连接

    git 本地项目与远程地址建立连接 建立好远程仓库与本地项目地址后 在本地项目文件夹内初始化git仓库 git init 复制远程项目路径地址,后执行: git remote add origin 远 ...

  3. 共建共荣金融生态!金融级数字底座“源启”与GoldenDB数据库完成互认证

    近日,中电金信金融级数字底座"源启"顺利与金篆信科GoldenDB分布式数据库完成互认证.GoldenDB数据库安全稳定运行在"源启"之上,整体性能表现卓越,进 ...

  4. 【C#】【平时作业】习题-6-静态成员

    习题-6静态成员 一.概念题 1. 什么是静态成员 被static修饰的成员,叫做静态成员.静态成员是属于类的.通过类名直接访问. 当类第一次被访问的时候,就会将这个类下面的所有的静态成员创建在内存当 ...

  5. 【前端】【H5 API】地理定位(获取经纬度)

    H5 API 地理定位 地理定位在日常生活中应用比较广泛,例如,互联网打车.在线地图等.在HTML 5的规范中,增加了获取用户地理位置信息的接口Geolocation,开发者可以通过经纬度来获取用户的 ...

  6. 龙哥量化:通达信DRAWICON的图标副图显示效果(鸡肋,可以不看)

    新建一个副图指标,复制粘贴源码,先看一下效果图 DRAWTEXT_FIX(1,0.01,0.01,0,'通达信中DRAWICON的图标,方便大家折腾指标'),COLORMAGENTA; A:=CURR ...

  7. Docker基础教程快速入门 Linux CentOS安装与使用Docker容器

    Docker 介绍 Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口.它是目前最流行的 Linux 容器解决方案. Docker 将应用程序与该程序的依赖,打包在一个文件里面 ...

  8. Qt音视频开发22-音频播放QAudioOutput

    一.前言 以前一直以为只有Qt5以后才有QAudioOutput播放音频,其实从Qt4.6开始就有,在Qt6中变成了QAudioSink,功能一样.用QAudioOutput播放音频pcm数据极其方便 ...

  9. Qt编写本地摄像头综合应用示例(qcamera/ffmpeg/v4l2等)

    一.功能特点 同时支持 qcamera.ffmpeg.v4l2 三种内核解析本地摄像头. 提供函数 findCamera 自动搜索环境中的所有本地摄像头设备,搜索结果信号发出. 支持自动搜索和指定设备 ...

  10. SINE:上下文示例驱动,打造真正的通用分割模型 | NeurIPS'24

    来源:晓飞的算法工程笔记 公众号,转载请注明出处 论文: A Simple Image Segmentation Framework via In-Context Examples 论文地址:http ...