Vue3:动态路由+子页面(新增、详情页)动态路由配置(代码全注释)

实现思路

   emm,项目中使用动态路由实现根据后端返回的用户详情信息,动态将该用户能够访问的页面信息,动态生成并且绑定到路由对象中。但是后端返回的不包含像是页面详情页,新增页的权限路由,如果前端在路由对象中写死的话,那每次进入页面都得判断是否将进入一个用户没有权限的页面,但是路由中有存在的。所以就想着自己能不能根据后端现有返回的信息,前端自己生成类似详情之类的动态路由。

调用后端接口获取用户页面权限动态绑定到路由对象中

1.获取用户权限

async function getUserAuthority(ids:any) {
   let userAuthority = null
   let NewList = null
    //定义请求参数
   let params = {
    id:ids,
     permission_tree:1
   }
   //请求用户的信息
   await get('/system/user/detail',params).then(res=>{
      if(res.status_code == 200){
        //userAuthority  存入查询到该用户信息 
        userAuthority = res.data
        //模拟该页面是需要跳转其他项目的地址
        let list =[{
          id: 119,
          children:[{
             id:1191,
             children:[],
             parent_id:119,
             name :'审单管理',
             slug:'web-system-exchangegoods-management',
             web_path : `/gongdan`,
             links:'https://blog.csdn.net/qq_45061461?type=lately'
          }],
          slug:'web-system-examineadocument',
          web_icon:'el-icon-coin',
          name :'审单管理',
          web_path: null,
          },
          {
            id: 117,
            children:[{
              children:[],
              id:1171,
              parent_id:117,
              slug:'web-system-exchangegoods-management',
              name :'换货留言列表',
              web_path : `/gongdan`,
              links:'https://so.csdn.net/so/search?q=vue3%3Amian,ts%E4%B8%AD%E8%8E%B7%E5%8F%96import.meta.glob&t=&u=&urw='
           }],
           slug:'web-system-exchangegoods',
           web_icon:'el-icon-coin',
           name :'换货留言列表',
           web_path: null,
            }
        ]
      
        //将后端返回的用户信息中的权限 和 自己定义的权限对象 合并一起
        NewList = userAuthority.permissions.concat(list);
        //将用户的权限信息保存本地中
        sessionStorage.setItem('NavList',JSON.stringify(NewList))
      }
   })
   return NewList
}

 2.用户登录请求信息 方法我就不写了

//调用定义的获取权限方法
proxy.$PublicAPI.getUserAuthority(list.user_id).then((res) => {
            //res就是上个方法中返回的权限信息 然后调用将路由添加入路由对象的方法
            proxy.$PublicAPI.getRouteAddList();
            //获取默认第一菜单的一个页面的路径进行跳转
            proxy.$PublicAPI.getOnePagePath();
          });

3.调用动态追加路由对象的方法

async function getRouteAddList() {
   <!--定义存放路由信息对象-->
  let parentRoute = null;
    <!--判断本地中是否存在权限信息-->
  if (sessionStorage.getItem('NavList')) {
    //list是 forEachRout方法返回的数据,将本地权限信息传入,根据信息生成路由对象格式数据
    let list =  forEachRout() 
    <!--router.getRoutes().find(route => route.name === 'index') 查找路由对象中的路由信息中name名为index的路由对象,name = index的路由对象path指向 index.vue 有显示页面元素的路由视图 <router-view /> -->
    parentRoute = router.getRoutes().find(route => route.name === 'index');
     <!--想自己生成的路由对象格式数据 追加到 /index中的chilrend中 -->
    list.forEach(item => {
      parentRoute.children.push(item);
    });
    <!--将定义好的路由数据格式对象添加到路由对象中-->
    router.addRoute(parentRoute);
  }
}

4.设计路由对象格式数据 forEachRout方法

function forEachRout  (){
  //存放已经设计好的路由对象
  let list = [] 
  //查找 ../../views/ 文件夹下所有的文件 views文件夹下是我存放的vue文件
  const module = import.meta.glob("../../views/**");
  <!-- 获取本地的权限信息 -->
  let params = JSON.parse(sessionStorage.getItem('NavList'));
  <!-- 循环遍历权限信息 -->
  params.forEach(item => {
  <!-- 判断权限信息中web_path 是否是为string,为string类型就是用户的页面权限 这是后端返回的 -->
    if (typeof item.web_path === 'string') {
    <!-- 设计路由对象格式信息 -->
      let routerChildrenOne = {
        path: item.web_path,
        name: `${item.web_path}`,
        component: module[`../../views${item.web_path}/index.vue`],
        meta: {
          title: item.name,
          buts: [],
          requireAuth: true,
          keepAlive: true,
          externalLink: item.links,
        }
      };
      <!-- 处理好的路由对象格式信息保存起来,后面存入路由对象中 -->
      list.push(routerChildrenOne);
      let butOne = item.slug;
      routerChildrenOne.meta.buts.push(butOne);
    } 
<!--  这个else 是判断是否需要跳转外部链接的对象,就是第一个截图中定义的两个权限数据对象 
-->
else {
      item.children.forEach(Citem => {
        let routerChildren = { 
           <!-- 判断对象中是否存在 links(跳转链接)属性,为存在的话,那么这个path将和其他同样存在links属性的对象公用一个页面(所有需要跳转外部的菜单都共同跳转这一个页面,所以这里使用了路由传参来确定点击他们不会只获取到最近的一个需要外部跳转的菜单,否则菜单中存在一个以上跳转外部菜单,无论点击哪一个都会跳转同一个外部链接。并菜单包含此path全部高亮),就会存在下方截图的错误-->
          path:Citem.links ? `${Citem.web_path}/:${Citem.id}` :  Citem.web_path ,
          name: `${Citem.web_path}`,
          component: module[`../../views${Citem.web_path}/index.vue`],
          meta: {
            title: Citem.name,
            buts: [],
            requireAuth: true,
            keepAlive: true,
            externallink:Citem.links
          }
        };
        list.push(routerChildren);
        Citem.children.forEach(C_item_C => {
          let but = C_item_C.slug;
          routerChildren.meta.buts.push(but);
        });
      });
    }
  });
  //返回定义好的路由格式对象
 return list
}

所以,在配置路由格式对象中外部跳转链接菜单通过动态路由传参来避免出现这个问题.到此菜单的动态路由已经配置完成。

动态添加子页面路由

但是我在想如果每个页面中都存在类似新增和详情的子页面,但是后端返回的信息中未包含,自己怎么也解决动态生成。于是就回到了,后端目前返回给我的权限信息,还有获取到veiws文件夹中的vue文件。

 1.后端返回的权限

2.veiws文件夹中已经存在的

3.实现,此方法就是 P4代码片段的方法 只不过增加了几个变量和调用了几个方法:

 新增变量名:Eligiblelimitsofauthority  , aa

 新增调用方法的方法名:UpdataRouterList 、GetPossibleDetails 

 已经底部retrun之前的判断对象是否存在component绑定的文件路由属性

function forEachRout  (){
  //存放已经设计好的路由对象
  let list = []
   <!-- 存放可能是新增页面,详情页面 和编辑页面的标识 -->
  let Eligiblelimitsofauthority = []
   <!-- 存放可能是新增页面,详情页面 和编辑页面的路由对象>
  let aa = [] 
  //查找 ../../views/ 文件夹下所有的文件 views文件夹下是我存放的vue文件
  const module = import.meta.glob("../../views/**");
  <!-- 获取本地的权限信息 -->
  let params = JSON.parse(sessionStorage.getItem('NavList'));
    
  <!-- 筛选出页面中出现可能是新增、详情或者编辑的信息 --> 
  UpdataRouterList(params,Eligiblelimitsofauthority)
  <!-- 根据传递过来的可能是详情或者编辑的信息,筛选出存在权限的数据,转换成路由格式对象 -->
  aa =  GetPossibleDetails(Eligiblelimitsofauthority,params,aa)


  <!-- 循环遍历权限信息 -->
  params.forEach(item => {
  <!-- 判断权限信息中web_path 是否是为string,为string类型就是用户的页面权限 这是后端返回的 -->
    if (typeof item.web_path === 'string') {
    <!-- 设计路由对象格式信息 -->
      let routerChildrenOne = {
        path: item.web_path,
        name: `${item.web_path}`,
        component: module[`../../views${item.web_path}/index.vue`],
        meta: {
          title: item.name,
          buts: [],
          requireAuth: true,
          keepAlive: true,
          externalLink: item.links,
        }
      };
      <!-- 处理好的路由对象格式信息保存起来,后面存入路由对象中 -- >
      list.push(routerChildrenOne);
      let butOne = item.slug;
      routerChildrenOne.meta.buts.push(butOne);
    } 
<!--  这个else 是判断是否需要跳转外部链接的对象,就是第一个截图中定义的两个权限数据对象 
-->
else {
      item.children.forEach(Citem => {
        let routerChildren = { 
           <!-- 判断对象中是否存在 links(跳转链接)属性,为存在的话,那么这个path将和其他同样存在links属性的对象公用一个页面(所有需要跳转外部的菜单都共同跳转这一个页面,所以这里使用了路由传参来确定点击他们不会只获取到最近的一个需要外部跳转的菜单,否则菜单中存在一个以上跳转外部菜单,无论点击哪一个都会跳转同一个外部链接。并菜单包含此path全部高亮),就会存在下方截图的错误-->
          path:Citem.links ? `${Citem.web_path}/:${Citem.id}` :  Citem.web_path ,
          name: `${Citem.web_path}`,
          component: module[`../../views${Citem.web_path}/index.vue`],
          meta: {
            title: Citem.name,
            buts: [],
            requireAuth: true,
            keepAlive: true,
            externallink:Citem.links
          }
        };
        list.push(routerChildren);
        Citem.children.forEach(C_item_C => {
          let but = C_item_C.slug;
          routerChildren.meta.buts.push(but);
        });
      });
    }
  });
   <!-- 判断转换成路由格式数据中component有数据的对象,component不为空的时候就是标识项目中已经创建了这个新增,详情 或编辑的页面-->
  if(aa){
     aa.map(item=>{
       if(item.component != undefined)
         list.push(item)
     })
  }
  //返回定义好的路由格式对象
 return list
}

2.UpdataRouterList方法 筛选出页面中出现可能是详情或者编辑的信息

//筛选出页面中出现可能是详情或者编辑的信息
function UpdataRouterList(navlist:any,Eligiblelimitsofauthority:any) {
   <!-- 循环传过来的本地权限数据对象中包含了 'create','edit' 和 'detail'的标识 -->
   navlist.map(item=>{
      if(item.slug.indexOf('create') != -1 || item.slug.indexOf('edit') != -1 || item.slug.indexOf('detail') != -1){
        <!-- 存入到可能包含新增,详情,编辑的标识数组中 -->
        Eligiblelimitsofauthority.push(item.slug)
      }
         <!-- 判断是否还有子数据,第一次循环的是下拉菜单 第二次循环的是下拉菜单中的点击跳转页面的菜单,第三次循环点击跳转页面的菜单中的 按钮权限,主要是拿到按钮权限菜单  这里是只有二级菜单,所以循环了三次,如果有多级也会一直循环下去,知道children中没有数据-->>
      if(item.children){
        UpdataRouterList(item.children,Eligiblelimitsofauthority)
      }
   })
}

3.GetPossibleDetails 根据传递过来的信息,筛选出存在权限的数据, 转换成路由信息,因为如果在本地中已经定义了全部的页面新增,详情,编辑等页面,但是咱们还是需要根据后端返回的权限中,判断咱们是否注册该页面的路由。

//根据传递过来的信息,筛选出存在权限的数据, 转换成路由信息 
function GetPossibleDetails(data:object,navlist:object,aa:any,) {
  <!-- 获取项目中views文件夹下的所有vue文件 -->
  const module = import.meta.glob("../../views/**");
  <!-- 遍历本地中的权限数据-->
   navlist.map(item=>{
   <!-- 传递过来的可能是 新增,详情,编辑的权限标识 -->
     data.map(ditem =>{
      <!-- 判断 item.web_path是否不为空,如果为空的话表明菜单是下拉菜单就不做操作 item.slug :这个菜单的标识 如:web-users 就是表示user(用户)菜单 -->
       if(item.web_path != null && ditem == `${item.slug}-create` || ditem == `${item.slug}-edit` ||  ditem == `${item.slug}-detail`){
        <!-- 存放定义的路由数据格式对象 -->
        let list = {}
        <!-- 截取item.we_path 菜单路径处理后的值,如:/user 我拿取user 后面作为/veiws/user,匹配views下的user文件夹 所以这里获取的是该菜单存放的文件夹名称 -->
        let path  = ''
        if(item.web_path != null){
           <!-- 截取文件夹名称 -->
          path = item.web_path.slice(item.web_path.lastIndexOf('/') + 1 , item.web_path.length)
           <!-- ditem是方法接收传递过来可能是新增,编辑,详情的权限标识数组,判断最后的-符号的后面是 'create':新增 ,'edit' :编辑 'detail':详情 -->
          switch ( ditem.slice(ditem.lastIndexOf('-') + 1 , ditem.length)) {
            case 'create':
               //如果是新增
              list = {
                //定义新增页面跳转的路由路径,如: path是截取到的文件名:user  那就path最后就是 :/usercreate
                path: '/'+path + 'create',
                name: `${path}create`,
                <!-- 匹配本地vue文件中是否包含 module:views下所有的vue文件,path:文件夹名称,item.web_path:vue文件名称 -->
                component: module[`../../views/${path}${item.web_path}create.vue`],
                meta: {
                  title: '新建' + item.name ,
                  buts: [],
                  requireAuth: true,
                  keepAlive: true,
                  externalLink: item.links,
                }
              }
              break;
            case 'edit':
              console.log('item-edit',item);
              list = {
                path: '/'+path + 'edit',
                name: `${path}edit`,
                component: module[`../../views/${path}${item.web_path}edit.vue`],
                meta: {
                  title: item.name  + '编辑' ,
                  buts: [],
                  requireAuth: true,
                  keepAlive: true,
                  externalLink: item.links,
                }
              }
            break;
          case 'detail':
            list = {
              path: '/'+path + 'detail',
              name: `${path}detail`,
              component: module[`../../views/${path}${item.web_path}detail.vue`],
              meta: {
                title:  item.name + '详情'  ,
                buts: [],
                requireAuth: true,
                keepAlive: true,
                externalLink: item.links,
              }
            }
            break;
         }
        }
        aa.push(list)
       }
     })
     <!-- 判断菜单中的chidren是否存在数据,如果没有存在就表明是一级点击跳转菜单,parent_id :0 表示的是菜单 -->
    if(item.children && item.parent_id == 0){
      GetPossibleDetails( data,item.children,aa)
     }
   })
   return aa
}

小结

1.最后添加到路由对象中的数据,最后一个对象就是新增的动态子页面路由

项目文件

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里以一个简的待办事项列表为例,实现增删改查功能。 1. 创建 Vue 组件 在 src/components 目录下创建 TodoList.vue 组件,代码如下: ```html <template> <div> <h2>待办事项列表</h2> <ul> <li v-for="(todo, index) in todos" :key="todo.id"> {{ todo.text }} <button @click="deleteTodo(index)">删除</button> </li> </ul> <form @submit.prevent="addTodo"> <input type="text" v-model="newTodoText" placeholder="添加新的待办事项"> <button type="submit">添加</button> </form> </div> </template> <script> export default { data() { return { todos: [ { id: 1, text: '学习 Vue.js' }, { id: 2, text: '学习 Vuex' }, { id: 3, text: '学习 Vue Router' } ], newTodoText: '' } }, methods: { addTodo() { if (this.newTodoText.trim()) { const newTodo = { id: Date.now(), text: this.newTodoText.trim() } this.todos.push(newTodo) this.newTodoText = '' } }, deleteTodo(index) { this.todos.splice(index, 1) } } } </script> ``` 这是一个简的待办事项列表组件,包含了待办事项的展示、添加和删除功能。todos 数组存储了待办事项列表,newTodoText 存储了新待办事项的文本。 2. 创建 Vue 路由 在 src/router/index.js 文件中创建路由,代码如下: ```js import Vue from 'vue' import VueRouter from 'vue-router' import TodoList from '../components/TodoList.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'TodoList', component: TodoList } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router ``` 这里只创建了一个路由,指向了 TodoList 组件。 3. 创建 Vuex Store 在 src/store/index.js 文件中创建 Vuex Store,代码如下: ```js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { todos: [ { id: 1, text: '学习 Vue.js' }, { id: 2, text: '学习 Vuex' }, { id: 3, text: '学习 Vue Router' } ] }, mutations: { addTodo (state, newTodoText) { if (newTodoText.trim()) { const newTodo = { id: Date.now(), text: newTodoText.trim() } state.todos.push(newTodo) } }, deleteTodo (state, index) { state.todos.splice(index, 1) } }, actions: { addTodo ({ commit }, newTodoText) { commit('addTodo', newTodoText) }, deleteTodo ({ commit }, index) { commit('deleteTodo', index) } }, getters: { todos: state => state.todos } }) ``` 这里的 state 对象中存储了待办事项列表,mutations 中定义了添加和删除待办事项的方法,actions 中定义了对应的异步操作,getters 中定义了获取待办事项列表的方法。 4. 在组件中使用 Vuex 在 TodoList.vue 组件中使用 Vuex,代码如下: ```html <template> <div> <h2>待办事项列表</h2> <ul> <li v-for="(todo, index) in todos" :key="todo.id"> {{ todo.text }} <button @click="deleteTodo(index)">删除</button> </li> </ul> <form @submit.prevent="addTodo"> <input type="text" v-model="newTodoText" placeholder="添加新的待办事项"> <button type="submit">添加</button> </form> </div> </template> <script> import { mapGetters, mapActions } from 'vuex' export default { computed: { ...mapGetters([ 'todos' ]) }, data() { return { newTodoText: '' } }, methods: { ...mapActions([ 'addTodo', 'deleteTodo' ]) } } </script> ``` 这里使用了 Vuex 的辅助函数 mapGetters 和 mapActions,分别将 todos 数组和添加、删除待办事项的方法映射到组件的 computed 和 methods 中。 5. 使用 Axios 获取数据 在 src/services/todoService.js 文件中定义获取待办事项列表的方法,代码如下: ```js import axios from 'axios' const API_URL = 'http://localhost:3000/todos' export function getTodos() { return axios.get(API_URL) .then(response => response.data) } ``` 这里使用了 Axios 库发送 HTTP 请求,获取待办事项列表。 6. 在组件中使用 Axios 和 Vuex 在 TodoList.vue 组件中使用 Axios 和 Vuex,代码如下: ```html <template> <div> <h2>待办事项列表</h2> <ul> <li v-for="(todo, index) in todos" :key="todo.id"> {{ todo.text }} <button @click="deleteTodo(index)">删除</button> </li> </ul> <form @submit.prevent="addTodo"> <input type="text" v-model="newTodoText" placeholder="添加新的待办事项"> <button type="submit">添加</button> </form> </div> </template> <script> import { mapGetters, mapActions } from 'vuex' import { getTodos } from '../services/todoService' export default { computed: { ...mapGetters([ 'todos' ]) }, data() { return { newTodoText: '' } }, methods: { ...mapActions([ 'addTodo', 'deleteTodo' ]), fetchTodos() { getTodos() .then(todos => { this.$store.commit('setTodos', todos) }) } }, created() { this.fetchTodos() } } </script> ``` 这里新增了 fetchTodos 方法,使用了 getTodos 方法获取待办事项列表,并将列表提交到 Vuex Store 中。在组件的 created 生命周期中调用 fetchTodos 方法,实现页面初始加载时获取待办事项列表的功能。 7. 完成 至此,我们已经完成了一个简的增删改查功能的待办事项列表应用。当用户打开应用时,页面会自动获取待办事项列表并展示出来。用户可以添加新的待办事项、删除已有的待办事项,并实时更新页面展示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值