vue-router4版本第一次打开界面不匹配路由问题

本文介绍了解决Vue项目中动态添加路由导致的路径匹配失败问题的方法。通过调整登录后的路由跳转逻辑,并在初始化菜单时正确使用next方法,解决了界面空白及警告问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:[Vue Router warn]: No match found for location with path “/home”
因为以前是一次性添加路由使用的是addRoutes,现在成了addRoute一个一个添加,我登陆后动态添加路由后,明明已经加了路由,打开却警告不匹配而且一片空白,然后查了说是需要

next({...to,replace:true})

这个…to,表示会再去一次这个路径,才能激活那个路径的匹配
以下是我的登录和加载菜单的逻辑和写法

login() {
  this.$refs.ruleForm.validate(valid => {
    if (valid) {
      this.axios.postForm('/login',this.loginForm).then(response => {
        let data = response.data;
        this.$store.commit('login', data)
        let redirect = this.$route.query.redirect
        this.$router.push({path: (redirect === undefined) ? '/home' : redirect});
      })

    } else {
      return false;
    }
  });
}

登录后会跳转,然后触发全局守卫

router.beforeEach((to, from, next) => {//配置路由守卫
    if(to.path==='/'){
        next()
    }else if(store.state.user.id){
        initMenus(router,store,next,to)
    }else{
        next({ path: '/',query: {redirect: to.path}});
    }
});

然后第一次会进入initMenus函数初始化路由

import axios from "axios";
export const initMenus = (router, store,next,to) => {//按F5刷新的话vuex里的会被清空,长度变为0
    if (store.state.menu !== null) {
        next()
    }else {
        axios.get("/menu").then(response => {
            if (response) {
                let responseData = response.data
                if (responseData.flag) {
                    store.state.menu = responseData.data
                    initRoute(router,store.state)
                    next({...to,replace:true})//解决router4版本的第一次路由不匹配问题
                } else {
                    this.$ElMessage.error('请求菜单失败')
                }
            }
        })
    }
}

const initRoute = (router,state)=> {
    const loadView = view => {//这种引入方式控制台不会报警告
        // 路由懒加载
        return () => import(`@/views/${view}`)
    };
    const menus = state.menu
    const firstLevelMenu = {
        children: [],
        component: loadView('home/HomeView.vue')
    }
    menus.forEach(menu=>{
        menu.component = loadView(menu.component)
        if(menu.children === null || menu.children.length === 0){
            firstLevelMenu.children.push(menu)
        }else{
            menu.children.forEach(children=>{
                children.component = loadView(children.component)
            })
            router.addRoute(menu)
        }
    })
    router.addRoute(firstLevelMenu)
}

一定要在添加完所有路由后写这个next({…to,replace:true}),而且next不能重复调用


最后可以解决界面空白问题,但是警告不会消失

### Vue3 RuoYi 框架 TopNav 默认选中并打开第一个页面的配置方法 在 Vue3 版本的若依框架中,为了实现顶部导航栏(TopNav)默认加载第一个子路由或菜单的功能,可以通过调整前端逻辑来完成。以下是具体的解决方案: #### 1. 调整路由匹配逻辑 通过修改 `src/router/index.js` 文件中的路由初始化逻辑,在应用启动时动态设置当前激活的菜单项。 如果检测到顶级菜单下存在多个子菜单,则自动选取第一个子菜单作为初始路径[^1]。可以利用 Vue Router 的编程式导航功能跳转至目标地址。 ```javascript import { useRouter } from 'vue-router'; const router = useRouter(); // 假设获取到了顶层菜单数据 menuList function setDefaultRoute(menuList) { const firstMenu = findFirstLeafMenu(menuList); if (firstMenu && firstMenu.path) { router.push(firstMenu.path); // 自动跳转到首个可用路径 } } function findFirstLeafMenu(menus) { for (let item of menus) { if (!item.children || !item.children.length) { return item; // 返回无子节点的第一个菜单 } let result = findFirstLeafMenu(item.children); // 递归查找 if (result) return result; } } ``` 上述代码片段定义了一个函数用于寻找最深一层叶子节点对应的 URL 地址,并调用 `router.push()` 方法执行页面切换操作。 #### 2. 更新状态管理模块 对于 Vuex 或 Pinia 状态管理系统来说,也需要同步更新当前活动菜单的状态值。例如可以在 store 中新增一个字段存储当前高亮显示的一级分类 ID 号码以及具体指向哪条记录的信息。 假设我们正在使用 Pinia 进行全局状态维护的话,那么就可以按照如下方式进行扩展处理: ```typescript // src/stores/menu.ts import { defineStore } from 'pinia'; export const useMenuStore = defineStore('menu', { state: () => ({ activeTopMenuId: '', // 当前活跃的顶栏ID currentSubMenuPath: '' // 当前所处的具体子页链接 }), actions: { setActiveMenu(topMenuId, subMenuPath){ this.activeTopMenuId = topMenuId; this.currentSubMenuPath = subMenuPath; } } }); ``` 当用户点击某个选项卡或者系统首次渲染完毕之后都会触发一次重新计算的过程从而决定到底应该突出哪一个部分的内容出来给访问者看到. #### 3. 修改模板绑定表达式 最后一步就是回到视图层面上去完善 HTML 结构设计的同时也要记得把刚才创建好的这些变量正确地嵌入进去形成完整的交互效果啦! 比如下面这个例子展示了如何结合前面提到过的两个核心组件一起工作起来达到预期目的的效果展示样式: ```html <template> <div class="app-container"> <!-- 头部区域 --> <a-layout-header :style="{ background: '#fff' }"> <top-nav @select="(key)=>handleSelect(key)" /> </a-layout-header> <!-- 主体内容区 --> <a-layout-content style="margin-top: 64px;"> <router-view v-slot="{ Component }"> <transition name="fade-transform" mode="out-in"> <component :is="Component"></component> </transition> </router-view> </a-layout-content> </div> </template> <script lang="ts"> import { ref, onMounted } from 'vue'; import { useMenuStore } from '@/stores/menu'; import { getMenusApi } from '@/api/system/menu'; export default { setup() { const menuStore = useMenuStore(); async function init(){ try{ const res=await getMenusApi(); const firstMenu=findFirstLeafMenu(res.data.list); if(firstMenu&&firstMenu.url){ menuStore.setActiveMenu(firstMenu.parentId||'',firstMenu.url); window.location.href=`${location.origin}${firstMenu.url}`; } }catch(err){} }; function handleSelect(selectedKey:string[]){ console.log(`Selected Key:${selectedKey}`); // 更改store里的activeTopMenuId 和currentSubMenuPath属性值... }; onMounted(() =>init()); return{handleSelect}; }, }; </script> ``` 以上即为基于 Vue3 技术栈下的 Ruoyi 后台管理系统项目里针对「顶部导航栏」实现「默认展开首屏可见的第一项业务单元详情界面」这一需求的整体解决思路概述. 其中涉及到了前后端配合的部分知识点包括但限于RESTful API接口调用、Vuex/Pinia 数据持久化机制运用等方面的知识要点.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值