文章目录

  • 使用场景
  • 一、动态菜单
    • 1.创建菜单组件
  • 二、动态面包屑
    • 1.创建面包屑组件
  • 三、动态标签页
    • 1.创建标签页组件
  • 四、动态路由
    • 1.router代码
    • 2.store代码
  • 总结

使用场景

主要使用Vue3与Element UI,在项目开发中可能会遇到从后端取得数据,到前端去渲染菜单,从而实现动态路由与动态菜单。


一、动态菜单

1.创建动态菜单组件

代码如下:

{{ menu.authname }}{{ item.authname }}.el-menu-item-group__title {display: none;}import { ref } from 'vue'import Tabs from '@/components/Tabs.vue';export default {name: 'Aside',created() {this.getrouter();},data() {return {openList: ['1'],menus: '',}},components: {Tabs},methods: {//登录界面请求网络已经拿到数据存入vuex,取出数据渲染使用;getrouter() {this.menus=this.$store.state.Routers},//点击子菜单触发事件getpath(path, authname, name, Menu_title ,Menu_path) {//将面包屑的数据传入vuex,方便面包屑数据变换this.$store.state.Breadcrumb_title = Menu_title;this.$store.state.Breadcrumb.title = authname;this.$store.state.Breadcrumb.path = path;this.$store.state.Breadcrumb.name = name;let tabs = this.$store.state.Tabs;const index = tabs.some(item => {if (item.title === authname) {return true;} else {return false;}})if (index === false) {//添加Tab标签页(将数据放入vuex存起来)let tab = {title: authname,name: name,path: path,};this.$store.state.Tabs.push(tab);this.$store.state.TabseditableTabsValue = name;} else {this.$store.state.TabseditableTabsValue = name;}this.$router.replace({path: "/index/"+path})},},}

二、动态面包屑

1.创建面包屑组件

代码如下:

.el-breadcrumb__item{cursor: pointer;}.el-breadcrumb__item .el-breadcrumb__inner{cursor: pointer;}首页{{this.$store.state.Breadcrumb_title}}{{this.$store.state.Breadcrumb.title}}export default {name: 'Breadcrumb',created(){},components: {},data() {return {Breadcrumb:this.$store.state.Breadcrumb,//从vuex中拿到面包屑数据并渲染}},methods:{},}

三、动态标签页

1.创建标签页组件

代码如下:

import store from '@/store/index.js';import router from '@/router/index.js';export default {name: 'Tabs',data() {return {editableTabs: store.state.Tabs,//从vuex获取Tabs的数据。tabIndex: 2}},methods: {//标签页被点击,则换面包屑数据。tabClick(tab,event) {store.state.Breadcrumb.title=tab.props.label;store.state.Breadcrumb.path='/index/'+tab.props.name;store.state.Breadcrumb.name=tab.props.name;router.replace({ path:'/index/'+tab.props.name })},//删除标签页,则选中前一个标签页,并激活其对应的路由页面。removeTab(targetName) {if (targetName == 'Home') {return}store.commit('delTabRouter', targetName)//在vuex找到方法delTabRouter,删除标签。if (store.state.TabseditableTabsValue == targetName) {// 设置当前激活的路由if (this.editableTabs && this.editableTabs.length >= 1) {store.state.Breadcrumb.title=this.editableTabs[this.editableTabs.length - 1].title;store.state.Breadcrumb.path='/index/'+this.editableTabs[this.editableTabs.length - 1].name;store.state.Breadcrumb.name=this.editableTabs[this.editableTabs.length - 1].name;store.commit('setActiveIndex', this.editableTabs[this.editableTabs.length - 1].name)router.replace({ path: this.editableTabs[this.editableTabs.length - 1].path })} else {router.replace({ path: '/index/Home' })store.state.TabseditableTabsValue = 'Home';store.commit('setTabRouter', { path: '/Home', name: 'Home', title: '员工信息表' })}}},},}

四、动态路由

1.router

index.js代码如下:

import { createRouter, createWebHistory } from 'vue-router'import store from '@/store';const routes = [//初始静态路由{path: '/',name: 'login',component: () => import('@/views/Login.vue'),},{path: '/index',name: 'Homepage',component: () => import('@/views/Homepage.vue'),redirect: '/index/Home',children: [{path: 'Home',name: 'Home',component: () => import('@/views/Home.vue'),}]},]const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes})var tag = true;//设置全局变量//路由拦截router.beforeEach(async (to, form, next) => {//第一次登录时,全局变量为true执行,第二次刷新,再次执行if (tag) {tag = false;if (to.name === 'login') {next()} else {let Routers = store.state.Routers;addRoutes(Routers);next(to.path);}} else {next()}})//添加路由的方法export function addRoutes(res) {res.forEach((Router, index) => {router.addRoute({path: Router.path,name: Router.name,component: () => import('@/views/' + Router.name + '.vue'),})let childrens = Router.children;if (childrens != undefined) {for (let i = 0; i  import('@/views/' + childrens[i].name + '.vue')})}}}})}export default router

2.store

index.js代码如下:

import { createStore } from 'vuex';import router from '@/router';export default createStore({state: {Routers: '',//登录获取的全部路由setAsyncRoutestMark: 'false',TabseditableTabsValue: 'Home',//当前选中Tab的名字Breadcrumb_title: '员工管理',//菜单栏标签//全部标签Tabs: [{title: '员工信息表',name: 'Home',path: '/index/Home',}],//选中的标签Breadcrumb: {title: '员工信息表',name: 'Home',path: '/index/Home'}},getters: {getTabs: state => {return state.Tabs;},getRouters: state => {return state.Routers;}},mutations: {//添加tabs路由setTabRouter(state, data) {state.Tabs.push(data)},// 删除tabs路由delTabRouter(state, data) {let index = 0;for (let option of state.Tabs) {if (option.path == data) {break}index++}state.Tabs.splice(index, 1);// 删完路由后也要保存到session中// sessionStorage.setItem('Tabs', JSON.stringify(state.Tabs))},// 设置当前激活的tabssetActiveIndex(state, index) {state.TabseditableTabsValue = indexstate.Breadcrumb.name = index;},},actions: {},modules: {}})


总结思路

1.路由守卫判定当初次登录时,后端返回路由数据,处理完数据放进vuex存起来。

2.(1)菜单组件去获取vuex的路由数据,进行处理形成自己需要的菜单数据并进行渲染。

(2)标签页组件去vuex获取Tabs数据,进行渲染。

(3) 面包屑直接从vuex里获取数据,进行渲染。

3. 操作(1)当子菜单栏被点击时,在vuex(即store)里面添加Tab数据,同时标签页、面包屑实时渲染。

操作(2)当标签页被删除时,在vuex里删除其数据,同时选中上一次点击的子菜单栏和标签页,面包屑也跟着变化

操作(3) 切换标签,动态菜单跟着切换选中

4. 当路由守卫判定不为初次登录时,则被认为是在刷新,则从sessionStorage缓存中找到数据赋值给store,重新渲染路由,使页面不为空白