vue3-动态添加路由-导航绑定路由

router/index.js

import { createRouter, createWebHashHistory } from 'vue-router'
// 引入 useStore
import { useStore } from '../store/index.js'



const routes = [
  {
    path: '/',
    redirect: '/order'
  },
  {
    path: '/login',
    name: 'login',
    component: () => import(/* webpackChunkName: "about" */ '../views/login.vue')
  },
  
]


// 动态路由,根据用户权限动态添加
const asyncRoutes = [
  {
    path: '/order',
    name: 'order',
    component: () => import(/* webpackChunkName: "about" */ '../views/navindex/order.vue'),
    redirect: '/order/awayorder',
    meta: {
        id:1,
        title: '订单管理',
        icon1:'order.png',
        icon2:'order2.png',
    },
    children: [
      {
        path: 'awayorder',
        name: 'awayorder',
        component: () => import(/* webpackChunkName: "about" */ '../views/awayorder.vue'),
        meta: {
          id:2,
          title: '收单管理',
        },
      },
      {
        path: 'sendorder',
        name: 'sendorder',
        component: () => import(/* webpackChunkName: "about" */ '../views/sendorder.vue'),
        meta: {
          id:3,
          title: '派单管理',
        },
      },
    ]
  },
  {
    path: '/system',
    name: 'system',
    component: () => import(/* webpackChunkName: "about" */ '../views/navindex/system.vue'),
    redirect: '/system/staffm',
    meta: {
        id:4,
        title: '系统管理',
        icon1:'set.png',
        icon2:'set2.png',
    },
    children: [
      {
        path: 'staffm',
        name: 'staffm',
        component: () => import(/* webpackChunkName: "about" */ '../views/staffm.vue'),
        meta: {
          id:5,
          title: '人员管理',
        },
      },
      {
        path: 'rolesm',
        name: 'rolesm',
        component: () => import(/* webpackChunkName: "about" */ '../views/rolesm.vue'),
        meta: {
          id:6,
          title: '角色管理',
        },
      },
    ]
  },
  //无子集页面
  {
    path: '/test',
    name: 'test',
    component: () => import(/* webpackChunkName: "about" */ '../views/test.vue'),
    
    meta: {
        id:20,
        title: '测试',
        icon1:'set.png',
        icon2:'set2.png',
    },
    
  },

]


const router = createRouter({
  history: createWebHashHistory(),
  routes
})

// 根据权限id,过滤要添加的路由的函数
function filterAsyncRoutes(routes, permissions) {
  const filteredRoutes = [];
  routes.forEach(route => {
    const newRoute = { ...route };
    //添加路由的条件,根据需求调整
    if (permissions.includes(route.meta?.id)) {
      if (route.children) {
        newRoute.children = filterAsyncRoutes(route.children, permissions);
      }
      filteredRoutes.push(newRoute);
    } else if (route.children) {
      const filteredChildren = filterAsyncRoutes(route.children, permissions);
      if (filteredChildren.length > 0) {
        newRoute.children = filteredChildren;
        filteredRoutes.push(newRoute);
      }
    }
  });
  
  return filteredRoutes;
}


// 添加动态路由的函数
function addDynamicRoutes(permissions) {

    // 清除旧的动态路由
  asyncRoutes.forEach(route => {
    router.removeRoute(route.name);
  });

  const filteredRoutes = filterAsyncRoutes(asyncRoutes, permissions);
  
  filteredRoutes.forEach(route => {
    router.addRoute(route);
  });

  // 因为watch无法监听都动态添加的路由,所以用pinia进行存储,让导航能使用到
  const store = useStore();
  store.addnowroute(filteredRoutes);

  console.log('filteredRoutes========')
  console.log(filteredRoutes)
  
}

// 处理页面刷新
router.beforeEach((to, from, next) => {
  //刷新重新加载路由
  if (to.path === '/login') {
    localStorage.removeItem('user');
    next();
    return;
  }
  if(JSON.parse(localStorage.getItem('user'))){
    const permissions = JSON.parse(localStorage.getItem('user')).permission;
    if (permissions && router.getRoutes().length === routes.length) {
      addDynamicRoutes(permissions);
      next({ ...to, replace: true });
    } else {
      next();
    }
  }else{
    next('/login');
  }
  
  
});






//导出方法,在登录后获取权限,进行动态路由添加
export {  addDynamicRoutes };
export default router;

pinia 

import { defineStore } from 'pinia'

export const useStore = defineStore('storeId',{
  state: ()=>{
    return {
    
      nowroute:[]
    } 
  },
  getters: {

  },
  actions: {
  
    addnowroute(arr){
      this.nowroute = arr
    },
  },
  // 开启数据缓存
  // persist:{
  //   enabled:true,
  //   strategies:[
  //     {
  //       key:'my_user',//储存的key
  //       storage:localStorage,//储存方式
  //       paths:['num']//储存数据,不要此项则储存所有数据
  //     }
  //   ]
  // }
})

login.vue

<template>
  <div class="home">
  
    <button @click="loginbtn">登录</button>
   
  </div>
</template>

<script setup>
import {login} from '@/assets/js/common.js'
import { inject ,onMounted,ref, reactive} from "vue";
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Delete, Edit, Search, Share, Upload, Plus, Close } from '@element-plus/icons-vue'
import {useStore} from '../store'
import { storeToRefs } from 'pinia';

// 重点!!!!!!!!!!
import { addDynamicRoutes } from '@/router/index'; // 引入封装的方法


//路由跳转
const router = useRouter()
//获取数据
const route = useRoute()

onMounted(() => {
    console.log('onMounted')
    
})

const loginbtn = ()=>{
  
  login({name: '三国演义',password: '111111'}).then((response)=>{
    console.log(response)


    
      // 模拟登录成功后获取权限数组
      const permissions = [ 2, 5,20];
      localStorage.setItem('permissions', JSON.stringify(permissions));

      // 添加动态路由
      addDynamicRoutes(permissions);

      //这里根据需求判断跳转页面
      router.push('/')


  })


}



   
</script>

app.vue

<el-menu
          style="background-color: #eff1f6;margin-top: 30px;"
            :default-active="nowpath"
            router
            @select="handleSelect"
        >
          <div class="t_nav_list_box" v-for="(item,index) in navlist.data" :key="index">
            <!-- 有子集的导航 -->
            <el-sub-menu v-if="item.children" :index="item.path" >
              <template #title>
                <img class="t_nav_icon" v-if="isStringIncluded(nowpath,item.path)" :src="getIconPath(item.meta.icon1)" alt="">
                <img class="t_nav_icon" v-else :src="getIconPath(item.meta.icon2)" alt="">
                <span style="margin-left: 5px;" :class="{'t_nav_color':isStringIncluded(nowpath,item.path)}">{{ item.meta.title }}</span>
              </template>
                <el-menu-item v-for="(item2,index2) in item.children" :key="index2" :index="item.path+'/'+item2.path">{{ item2.meta.title }}</el-menu-item>
            </el-sub-menu>
            <!-- 无子集的导航 -->
            <el-menu-item v-else :index="item.path" >
              <img class="t_nav_icon" v-if="isStringIncluded(nowpath,item.path)" :src="getIconPath(item.meta.icon1)" alt="">
                <img class="t_nav_icon" v-else :src="getIconPath(item.meta.icon2)" alt="">
              <span  style="margin-left: 5px;">{{ item.meta.title }}</span>
            </el-menu-item>
          </div>
          
        </el-menu>




// 引入 useStore
import { useStore } from '@/store'; 
import { storeToRefs } from 'pinia';
const store = useStore();
let {nowroute} = storeToRefs(store)




//菜单列表
const navlist = reactive({
  data:[]
})


//当前路由
const nowpath = ref('/order')

/js判断当前父级路由是否是当前选中的子集路由,改变图标颜色和子集颜色
const isStringIncluded = (str, target)=> {
    return str.includes(target);
}

// 计算属性,生成选中状态的图标路径
const getIconPath = (path) => {
  
  return  require(`../src/assets/img/${path}`)
}



//监听当前路由
onMounted(() => {
  //从pinia拿到当前动态添加的路由,赋值给导航栏
  navlist.data = nowroute;
})

//监听当前路由
watch(() => router.currentRoute.value.path, (newValue, oldValue) => {
  //获取所有路由
  // var allroute = proxy.$router.options.routes
  
  nowpath.value = newValue

  

}, { immediate: true, deep: true })

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

T-小丑

需要什么demo可以留言

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值