文章目录

  • 使用场景
  • 一、动态菜单

    • 1.创建菜单组件
  • 二、动态面包屑

    • 1.创建面包屑组件
  • 三、动态标签页

    • 1.创建标签页组件
  • 四、动态路由

    • 1.router代码
    • 2.store代码
  • 总结

使用场景

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

一、动态菜单

1.创建动态菜单组件

 代码如下:

<template>
  <div>
    <el-menu :unique-opened="true" :default-openeds="openList"
      :default-active="'/index/' + this.$store.state.TabseditableTabsValue" :collapse-transition="true" router
      class="el-menu-vertical-demo" style="width: 200px;min-height: calc(100vh );">
      <el-sub-menu v-for="(menu, i) in menus" :index="i + 1" :key="i">
        <template #title>
          <el-icon>
            <Avatar />
          </el-icon>
          <span>{{ menu.authname }}</span>
        </template>
        <el-menu-item-group>
          <el-menu-item @click="getpath(item.path, item.authname, item.name, menu.authname ,menu.path)"
            :index="'/index/' + item.path" v-for="(item, index) in menu.children" :key="index">
            <el-icon>
              <ArrowRight />
            </el-icon>{{ item.authname }}
          </el-menu-item>
        </el-menu-item-group>
      </el-sub-menu>
    </el-menu>
  </div>
</template>
<style>
.el-menu-item-group__title {
  display: none;
}
</style>
<script>
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})
    },
  },
}
</script>

二、动态面包屑

1.创建面包屑组件

代码如下:

<style>
.el-breadcrumb__item{
  cursor: pointer;
}
.el-breadcrumb__item .el-breadcrumb__inner{
  cursor: pointer;
}
</style>
<template>
  <el-breadcrumb  style="transform: translate(-12%,-50%);margin-left: 10.7%;padding: 10px;">
    <el-breadcrumb-item>首页</el-breadcrumb-item>
    <el-breadcrumb-item >{{this.$store.state.Breadcrumb_title}}</el-breadcrumb-item>
    <el-breadcrumb-item  replace :to="{path:Breadcrumb.path}" >{{this.$store.state.Breadcrumb.title}}</el-breadcrumb-item>
  </el-breadcrumb>
</template>
<script>
export default {
  name: 'Breadcrumb',
  created(){
  },
  components: {
  },
  data() {
    return {
      Breadcrumb:this.$store.state.Breadcrumb,//从vuex中拿到面包屑数据并渲染
    }
  },
  methods:{
  },
}
</script>

 三、动态标签页

1.创建标签页组件

代码如下:

<template>
  <el-tabs v-model="this.$store.state.TabseditableTabsValue" type="card" @tab-click="tabClick" closable
    @tab-remove="removeTab">
    <el-tab-pane v-for="(item, index) in editableTabs" :key="index" :label="item.title" :name="item.name"></el-tab-pane>
  </el-tabs>
</template>
<script>
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: '员工信息表' })
        }
      }
    },
  },
}
</script>

 四、动态路由

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 < childrens.length; i++) {
        if (childrens[i] != undefined) {
          router.addRoute('Homepage', {
            path: childrens[i].path,
            name: childrens[i].name,
            component: () => 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))
    },
    // 设置当前激活的tabs
    setActiveIndex(state, index) {
      state.TabseditableTabsValue = index
      state.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,重新渲染路由,使页面不为空白

发表回复