【摸鱼神器】一次搞定 vue3的 路由 + 菜单 + tabs

您所在的位置:网站首页 设置主页是利用哪个菜单 【摸鱼神器】一次搞定 vue3的 路由 + 菜单 + tabs

【摸鱼神器】一次搞定 vue3的 路由 + 菜单 + tabs

2024-07-02 10:17| 来源: 网络整理| 查看: 265

做一个管理后台,首先要设置路由,然后配置菜单(有时候还需要导航),再来一个动态tabs,最后加上权限判断。

这个是不是有点繁琐?尤其是路由的设置和菜单的配置,是不是很雷同?那么能不能简单一点呢?如果可以实现设置一次就全部搞定的话,那么是不会很香呢?

我们可以简单封装一下,实现这个愿望。

定义一个结构

我们可以参考 vue-router 的设置 和 el-menu 的参数,设置一个适合我们需求的结构:

./router.js代码语言:javascript复制import { createRouter } from '@naturefw/ui-elp' import home from '../views/home.vue' const router = { /** * 基础路径 */ baseUrl: baseUrl, /** * 首页 */ home: home, menus: [ { menuId: '1', // 相当于路由的 name title: '全局状态', // 浏览器的标题 naviId: '0', // 导航ID path: 'global', // 相当于 路由 的path icon: FolderOpened, // 菜单里的图标 childrens: [ // 子菜单,不是子路由。 { menuId: '1010', // 相当于路由的 name title: '纯state', path: 'state', icon: Document, // 加载的组件 component: () => import('../views/state-global/10-state.vue') // 还可以有子菜单。 }, { menuId: '1020', title: '一般的状态', path: 'standard', icon: Document, component: () => import('../views/state-global/20-standard.vue') } ] }, { menuId: '2000', title: '局部状态', naviId: '0', path: 'loacl', icon: FolderOpened, childrens: [ { menuId: '2010', title: '父子组件', path: 'parent-son', icon: Document, component: () => import('../views/state-loacl/10-parent.vue') } ] } ] } export default createRouter(router )

在 Router 的配置的基础上,加上 title、icon等菜单需要的属性,基本就搞定了。

baseUrl:如果不能发布到根目录的话,需要设置一个基础URL。home:默认显示的组件,比如大屏。menus:路由、菜单集合。 naviId:导航ID。menuId:相当于路由的 name。path:相当于 路由 的path。title:浏览器的标题。icon: 菜单里的图标。childrens:子菜单,不是子路由。main 里面加载。

设置之后,我们在main里面挂载一下即可。

代码语言:javascript复制import { createApp } from 'vue' import App from './App.vue' // 简易路由 import router from './router' createApp(App) .use(router) .mount('#app')看看效果路由和菜单路由和菜单

https://naturefw-code.gitee.io/nf-rollup-state/class/object

这样就搞定了,是不是很简单,因为我们把其他代码都封装成了组件。

封装 n级菜单

我们可以基于 el-menu,封装一个动态n级菜单组件(nf-menu)。

菜单组件可以基于 el-menu 封装,也可以基于其他组件封装,或者自己写一个,这里以el-menu为例,介绍一下封装方式:

父级菜单代码语言:javascript复制

父级菜单比较简单,设置 el-menu 需要的属性,然后加载子菜单组件。

n级子菜单代码语言:javascript复制 {{item.title}} {{item.title}} 树枝:含有子菜单的菜单,使用 el-sub-menu 实现,不加载组件。树叶:没有子菜单,使用 el-menu-item 实现,加载组件的菜单。图标:使用 component 加载图标组件。

然后设置属性即可,这样一个n级菜单就搞定了。

封装一个动态tabs

菜单有了,下一步就是tabs,为了满足不同的需求,这里封装两个组件,一个单tab的,一个是动态多tabs的。

单 tab 参考 Router 的 router-view 封装一个组件 nf-router-view:代码语言:javascript复制

直接使用 component 加载组件即可。

动态多tabs 基于 el-tabs 封装一个动态多tabs组件 nf-router-view-tabs:代码语言:javascript复制 {{$router.menuList[key].title}} ;

为了保持状态,这里采用了一个笨办法,点击菜单加载的组件都放在 el-tab-pane 里面,通过切换 tab 的方式显示组件。

源码:https://gitee.com/naturefw-code/nf-rollup-ui-controller

做一个简单的路由

看了半天,你有没有发现,似乎缺少了一个重要环节?

你猜对了,路由的封装还没有介绍。

这里并不想设计一个像 vue-router那样的全能路由,而是设计一个适合管理后台的简易路由。

菜单是多级的,url 也是多级的和菜单对应,但是路由是单级的,不嵌套。

也就是说,点击任意一级的(树叶)菜单,加载的都是同级的组件。

另外暂时不考虑加载组件后的路由的设置。我觉得,这个可以交给加载的组件自行实现。

代码语言:javascript复制import { defineAsyncComponent, reactive, watch, inject } from 'vue' const flag = Symbol('nf-router-menu___') /** * 一个简单的路由 * @param { string } baseUrl 基础路径 * @param { components } home 基础路径 * @param { array } menus 路由设置,数组,多级 * * [{ * * * menuId: '菜单ID' * * * naviId: '0', // 导航ID,可以不设置 * * * title: '标题', * * * path: '路径', * * * icon: Edit, // 图标组件 * * * component: () => import('./views/xxx.vue') // 要加载的组件,可以不设置 * * * childrens: [ // 子菜单,可以多级 * * * * { * * * * * menuId: '菜单ID' * * * * * title: '标题', * * * * * path: '路径', * * * * * icon: Edit, // 图标组件 * * * * * component: () => import('./views/xxx.vue') // 要加载的组件 * * * * } * * * ] * * }, * * 其他菜单 * * ] * @returns */ class Router { constructor (info) { // 设置当前选择的路由 this.currentRoute = reactive({ key: 'home', // 默认的首页 paths: [] // 记录打开的多级菜单的信息 }) this.baseUrl = info.baseUrl // 基础路径,应对网站的二级目录 this.baseTitle = document.title // 初始的标题 this.isRefresh = false // 是否刷新进入 this.home = info.home // 默认的首页 this.menus = reactive(info.menus) // 菜单集合,数组形式,支持多级,可以设置导航ID this.menuList = {} // 变成单层的树,便于用key查找。 this.tabs = reactive(new Set([])) // 点击过且没有关闭的二级菜单,做成动态tab标签 this.setup() } /** * 初始化设置 */ setup = () => { // 监听当前路由,设置 tabs 和标题、url watch(() => this.currentRoute.key, (key) => { 略 }) } /** * 添加新路由,主要是实现根据用户权限加载对应的菜单。 */ addRoute = (newMenus, props = {}) => { 略 } /** * 删除路由 * @param { array } path 菜单的路径,[] 表示根菜单 * @param { string | number } id 要删除的菜单ID */ removeRoute = (path = [], id = '') => { 略 } /** * 刷新时依据url加载组件 */ refresh = () => { 略 } /** * 加载路由指定的组件 * @returns */ getComponent = () => { if (this.currentRoute.key === '' || this.currentRoute.key === 'home') { return this.home } else { return this.menuList[this.currentRoute.key].component } } /** * 删除tab * @param { string } key * @returns */ removeTab = (key) => { 略 } /** * 安装插件 * @param {*} app */ install = (app) => { // 便于模板获取 app.config.globalProperties.$router = this // 便于代码获取 app.provide(flag, this) } } /** * 创建简易路由 */ const createRouter = (info) => { // 创建路由, const router = new Router(info) // 判断url,是否需要加载组件 setTimeout(() => { router.refresh() }, 300) // 使用vue的插件,设置全局路由 return router } /** * 获取路由 * @returns */ const useRouter = () => { return inject(flag) } export { createRouter, useRouter }

篇幅有限,这里只介绍了路由的整体结构,具体实现方式可以看源码:

源码:https://gitee.com/naturefw-code/nf-rollup-ui-controller

菜单与权限

上面是静态的路由和导航的设置方式,对于管理后台,必备的一个需求就是,根据用户的权限来加载路由和菜单。

所以我们提供了一个 addRoute 方法,实现动态添加路由的功能,这样可以等用户登录之后,得到用户的权限,然后按照权限加载路由和菜单。

代码语言:javascript复制 const router = useRouter() router.addRoute([ { menuId: 'dt-100', title: '添加根菜单', naviId: '0', path: 'new-router', icon: FolderOpened, childrens: [ { menuId: '100-10', title: '动态菜单', path: 'ui', icon: Document, component: () => import('../ui/base/c-01html.vue') } ] } ], { index: 1 })

同时也可以加上权限判断。菜单是基于 el-menu 实现的,可以加上 select 事件,然后在事件里面判断权限,如果没有权限可以跳转到登录组件。

代码语言:javascript复制const router = useRouter() const myselect = (index, indexPath) => { // 验证权限,如果没有权限,加载登录组件 if (没有权限) { router.currentRoute.paths = '' router.currentRoute.key = '登录组件的key' } }示例项目

https://gitee.com/naturefw-code/nf-rollup-state



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3