Vue 系列之:路由

vue-router 组件

router-link

  • 功能:用于导航,即渲染一个链接,当点击时,导航到由 to 属性指定的 URL。

  • 示例:<router-link to="/home">Home</router-link>

  • 它会渲染为一个 <a> 标签,但如果你希望它渲染为其他标签,你可以使用 tag 属性,如 <router-link to="/home" tag="li">Home</router-link>。

router-link 的一些属性:

  • to:必填,标识目标路由的链接,当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者描述目标路由的对象

  • repalce:默认值 false,若设置的话,当点击时,会调用 router.replace() 而不是 router.push()

  • append:设置 append 属性后,则在当前 (相对) 路径前添加基路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b

  • event:声明可以用来触发导航的事件,可以是一个字符串或是一个包含字符串的数组,默认是 click

  • exact:是否精确匹配,默认为 false。例如,路径 /user 精确匹配只会匹配 /user,而不会匹配 /user/123 或 /user/abc。默认匹配就会匹配任何以 /user 开头的路径

  • tag:让 <router-link> 渲染成 tag 设置的标签,如 tag=“li”,就会渲染成 <li>跳转</li>

  • active-class:默认值为 router-link-acitve,设置链接激活时使用的 CSS 类名,默认值可以通过路由的构造选项 linkActiveClass 来全局配置

  • exact-active-class:默认值为 router-link-exact-active,设置链接被精确匹配的时候应该激活的 class,默认值可以通过路由构造函数选项 linkExactActiveClass 进行全局配置

router-view

  • 功能:组件的出口,即路由匹配到的组件将渲染在这里。

  • 它可以理解为是一个占位符,Vue Router 会根据当前路由规则动态地替换显示相应的组件。

  • 通常放在 App 组件的模板中,作为整个应用的布局中心。

vue-router 功能

嵌套路由

Vue Router 嵌套路由指的是在一个路由的基础上,再嵌套其他子路由,用于构建更复杂的页面层级结构,让页面组件可以进行嵌套展示。

例如点击顶部导航栏,左边显示不同的菜单栏。

<template><div id="app"><h1>初始页面</h1><router-link to="/home">Home</router-link><!-- 路由出口,根据当前的路由状态渲染匹配到的组件内容 --><!-- 当点击上面的链接时此处会显示 Home 组件的内容 --><router-view></router-view></div>
</template><script>
export default {name: 'App'
}
</script>
<!-- Home.vue -->
<template><div><h1>Welcome to Home</h1><router-link to="/about">About</router-link><router-link to="/team">Team</router-link><router-view></router-view> <!-- 嵌套路由的出口 --></div>
</template>
// router/index.js
import Home from '@/components/Home'
import About from '@/components/About'
import Team from '@/components/Team'export default new Router({routes: [{path: '/home',component: Home,children: [{path: '/about',component: About},{path: '/team',component: Team}]}]
})

动态路由参数

Vue Router 支持动态路由参数,如 /user/:id,其中 :id 是一个动态参数。

带参数跳转:

$router.push(`/user/${this.userId}`);

获取参数:

$route.params.id

路由传递数据

有 query 传参和 params 两种传递数据方式,后面会详细说明。

供路由守卫

提供路由守卫,允许你在导航过程中执行自定义逻辑来拦截导航并改变其行为。

HTML5 history 和 hash 模式

Vue Router 支持两种 URL 模式:HTML5 history 模式和 hash 模式。

HTML5 history 模式使用浏览器的历史记录 API 来管理 URL,而 hash 模式则使用 URL 的 hash 部分来模拟页面跳转。

在支持 HTML5 history API 的现代浏览器中,推荐使用 HTML5 history 模式以获得更好的 URL 体验。

URL 的正确编码

Vue Router 会自动对 URL 进行正确的编码和解码,以确保 URL 的有效性和可读性。

当你需要传递特殊字符或 URL 片段时,Vue Router 会确保这些字符被正确地处理。

过渡效果

可以使用 Vue 的 <transition> 组件来定义过渡效果。

自动激活 CSS 类的链接

Vue Router 会自动为当前激活的链接添加一个 CSS 类名,这通常用于高亮当前激活的导航链接。

你可以通过配置 linkActiveClass 选项来自定义这个类名。

<!--方法一-->
<router-link to='/' active-class="active" >首页</router-link><!--方法二-->
<script>
const router = new VueRouter({routes,linkActiveClass: 'active'
});
</script>

可定制的滚动行为

Vue Router 允许你定制页面跳转时的滚动行为。

你可以通过配置 scrollBehavior 函数来定义滚动行为。

例如切换到新路由时,页面要滚动到顶部或保持原先的滚动位置。

const router = createRouter({scrollBehavior(to, from, savedPosition) {// 始终滚动到顶部return { top: 0 }},
})

官方示例

vue-router 跳转方式

声明式导航

通过内置组件 router-link 跳转

<router-link to="/home"></router-link>

编程式导航

通过调用 router 实例的方法跳转

this.$router.push({name: 'myPage',params: {...}
});this.$router.push({path: '/myPage',query: {...}
});this.$router.push('/myPage');this.$router.replace({name: 'myPage',params: {...}
});this.$router.replace({path: '/myPage',query: {...}
});

注意:name 对应 params,path 对应 query。

query 和 params 的区别

  • query 传参会显示在 url 地址上,params 传参不会显示地址上

  • query 刷新页面参数不会消失,params 传参页面参数会消失,可以考虑本地存储解决

this.$router.push({path: '/test',query: { id: 123 }
});
/*
url 格式:http://xxx/test?id=123
模板内获取数据:this.$route.query.id
*/this.$router.push({name: 'test',params: { id: 123 }
});
/*
url 格式:http://xxx/test
模板内获取数据:this.$route.params.id
*/this.$router.push({path: '/path/${id}'
});
/*
url 格式:http://xxx/test/123
模板内获取数据:this.$route.params.id
组件路由:/test:id
*/

再次注意:name 对应 params,path 对应 query。

$router.push 和 $router.replace 的区别

  • $router.push:

    这个方法会向浏览器历史记录中添加一个新的记录。

    也就是说,当你调用 $router.push 跳转到一个新的路由时,用户点击浏览器的“返回”按钮时,会返回到之前的页面。

  • $router.replace:

    这个方法会替换当前的历史记录,新的路由会替代当前路由的位置。

    也就是说,当你调用 $router.replace 跳转时,浏览器历史记录不会增加新的一项,而是用新的路由替代当前的路由。如果用户点击“返回”按钮,会跳回到替换前的那个页面。

vue-router 两种模式

Hash 模式

URL 形式:

Hash 模式的 URL 包含 # 符号,后面跟着路由路径。例如:http://example.com/#/home,其中 /home 是路由路径。

原理:

Hash 模式利用浏览器对 URL 中 # 符号的特殊处理。# 后面的部分被视为锚点,通常用于滚动页面至特定位置。

在 Vue Router 中,当 URL 的 hash 值变化时(无论是通过点击链接、编程式导航,还是手动修改地址栏并按回车),浏览器不会发送请求到服务器,而是触发 hashchange 事件。Vue Router 会监听该事件,并根据新的 hash 值匹配对应的路由组件进行渲染。

特点:

  • 兼容性好: 由于 # 符号被所有现代浏览器支持,Hash 模式能在各类浏览器上正常工作,且对老旧浏览器也有较好的兼容性。

  • 部署简单: Hash 模式不需要服务器特殊配置,因为 # 后的内容不会被发送到服务器。

  • SEO 性能差: 搜索引擎通常忽略 # 后的内容,因此 Hash 模式不利于 SEO。

  • URL 不美观: URL 中包含 # 符号,可能显得不够美观,尤其对不熟悉 SPA 的用户来说。

注意:

前面说到当 URL # 后面的内容发生变化时,浏览器不会发送请求到服务器。这是因为:在单页面应用中,所有的页面内容(HTML、CSS、JavaScript 等)在初始加载时就已经从服务器获取并加载到浏览器内存中了。后续切换路由,实际上是在已经加载的页面基础上,通过 JavaScript 操作 DOM 来显示或隐藏不同的内容区域,实现类似页面切换的效果,而不是像传统的多页面应用那样,每次页面切换都要从服务器获取全新的 HTML 页面。

History 模式

也叫 HTML5 模式。

URL 形式:

History 模式下的 URL 整洁,无 # 符号,呈现常规路径结构,如:http://example.com/home。

原理:

利用 HTML5 的 History API(history.pushState() 和 history.replaceState() )实现 URL 跳转和状态管理。

Vue Router 在该模式下,当用户点击路由链接或通过 JavaScript 代码调用 router.push (‘/new-path’) 时,会使用 pushState() 或 replaceState() 方法更新浏览器历史记录和浏览器当前 URL。同时,Vue Router 监听 popstate 事件捕获浏览器的前进后退操作,并依据新 URL 计算对应路由,动态加载组件。

特点:

  • URL 美观性好:没有 #,符合传统网站链接的预期。

  • SEO 性能较好:搜索引擎更容易抓取和索引。

  • 需要服务器配置:需要配置服务器使得直接访问 URL 时能够返回应用的入口页面(如 index.html)。

  • 兼容性问题:现代浏览器支持良好,但老版本浏览器可能存在兼容性问题。

注意:

当用户通过 Vue Router 的导航(例如点击 <router-link> 或调用 router.push())切换路由时,URL 会发生变化,但不会向服务器发送请求。Vue Router 会在浏览器内存中动态渲染对应的组件,而不会重新加载页面或从服务器获取新的内容。

但是当用户直接在浏览器地址栏中输入一个 URL(例如 http://example.com/home)或者刷新页面时,浏览器会向服务器发送一个请求,要求获取该 URL 对应的资源。

  • 如果服务器没有正确配置(例如没有将所有路由请求重定向到 index.html),服务器会尝试查找 /home 对应的文件或资源。由于这个路径在服务器上并不存在,服务器会返回 404 错误。

  • 如果服务器配置正确(例如将所有路由请求重定向到 index.html),服务器会返回 index.html 文件。浏览器加载 index.html 后,Vue Router 会根据当前的 URL(例如 /home)在浏览器内存中渲染对应的组件。

这与 Hash 模式不同,在 Hash 模式 下,直接在浏览器地址栏中输入 URL 并访问是不会向服务器发起网络请求的。所以 Hash 模式不需要将所有路由请求重定向到 index.html。

注意这一章节中的路由都是静态路由,如果是懒加载路由,情况又会有所不同。

vue-router 懒加载

Vue 路由懒加载是指在用户访问某个路由时,才动态加载该路由对应的组件代码,而不是在应用程序初始化时就加载所有组件。这种按需加载的方式可以有效提高页面加载速度和应用程序性能。

路由懒加载的核心思想是将路由对应的组件打包成单独的文件,在需要的时候再进行加载。当用户首次访问某个使用了路由懒加载的路由时,由于该组件对应的文件还没有被加载到浏览器内存中,所以需要向服务器发起请求来获取这个组件的代码。

懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。

未用懒加载

import Vue from 'vue'
import Router from 'vue-router'import HelloWorld from '@/components/HelloWorld'Vue.use(Router)export default new Router({routes: [{path:'/',name: 'HelloWorld',component: HelloWorld}]
})

webpack 动态导入实现懒加载

import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)export default new Router({routes: [{path: '/',name: 'HelloWorld',component: resolve=>require(["@/components/HelloWorld"] , resolve)}]
})

ES6 import() 实现懒加载

最常用

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)export default new Router({routes: [{path: '/',name: 'HelloWorld',component: ()=>import("@/components/HelloWorld")}]
})

vue-router 中的导航钩子

作用:在路由导航发生前后执行特定逻辑,例如权限验证、完成或取消路由跳转等。

有三种方式可以植入到路由导航过程中:

  • 全局守卫:全局的

  • 路由独享守卫:单个路由独享的

  • 组件内守卫:组件级的

全局守卫

全局前置守卫:beforeEach

作用:在路由切换之前被调用,每次路由切换都会触发。

参数:

  • to:即将进入的目标路由对象。

  • from:当前导航正要离开的路由对象。

  • next:必须调用该方法来 resolve 这个钩子。

    • next():允许导航。

    • next(false):中断当前的导航。

    • next(‘/’) 或 next({ path: ‘/’ }):当前导航被中断,进行新的一个导航。

    • next(error):导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

示例:

const router = new VueRouter({... })
router.beforeEach((to, from, next) => {const isAuthenticated = localStorage.getItem('isAuthenticated');if (to.meta.requiresAuth &&!isAuthenticated) {next('/login');} else {next();}
});

全局解析守卫:beforeResolve

作用:在 beforeEach 之后,beforeEnter 之前,并且在所有组件内守卫和异步路由组件被解析之后调用。主要用于确保在进入路由之前,所有的异步组件都已经解析完成。很少用到。

参数:和 beforeEach 相同,即 to、from、next。

示例:

router.beforeResolve((to, from, next) => {// 可以在这里做一些等待异步组件解析完成的操作next();
});

全局后置钩子:afterEach

作用:每次路由跳转结束后调用,它不接受 next 参数,因此不能阻止导航。通常用于统计和日志记录。

参数:

  • to:成功跳转的目标路由对象。

  • from:离开的路由对象。

示例:

router.afterEach((to, from) => {// 进行页面统计或日志记录console.log(`从 ${from.name} 跳转到了 ${to.name}`);
});

路由独享守卫:beforeEnter

beforeEnter(to, from, next):在进入特定路由前执行,配置在路由配置对象中。

参数与 beforeEach 相同。

示例:

const router = new VueRouter({routes: [{path: '/admin',component: AdminComponent,beforeEnter: (to, from, next) => {const isAdmin = localStorage.getItem('isAdmin');if (isAdmin) {next();} else {next('/');}}}]
});

组件内守卫

beforeRouteEnter

作用:在进入该组件的对应路由时调用,此时组件实例还未被创建,所以不能访问 this。

参数:

  • to:即将要进入的目标路由对象。

  • from:当前导航正要离开的路由对象。

  • next:next 函数可以接收一个回调函数作为参数,该回调函数在组件实例被创建后调用,并且可以将 this 作为参数传递给回调函数,以便在组件内进行操作。

    注意:只有 beforeRouteEnter 支持给 next 传递回调。

示例:

export default {beforeRouteEnter(to, from, next) {next((vm) => {// vm 是组件实例vm.initData();});},methods: {initData() {// 初始化数据的方法}}
};

beforeRouteUpdate

作用:在当前路由改变,但是该组件被复用时调用,例如在一个带有参数的动态路由中,参数变化时,组件实例不会重新创建,此时会调用这个钩子。

参数:

  • to:即将要进入的目标路由对象。

  • from:当前导航正要离开的路由对象。

  • next:和其他钩子中的 next 函数作用相同。

示例:

export default {beforeRouteUpdate(to, from, next) {// 处理参数变化后的逻辑this.fetchData(to.params.id);next();},methods: {fetchData(id) {// 获取数据的方法}}
};

beforeRouteLeave

作用:在离开该组件的对应路由时调用,可以用于防止用户未保存数据就离开页面等场景。

参数:

  • to:即将要进入的目标路由对象。

  • from:当前导航正要离开的路由对象。

  • next:和其他钩子中的 next 函数作用相同。

示例:

export default {beforeRouteLeave(to, from, next) {const isDataSaved = this.isDataSaved();if (isDataSaved) {next();} else {if (confirm('数据未保存,是否离开?')) {next();} else {next(false);}}},methods: {isDataSaved() {// 判断数据是否已保存的方法}}
};

导航守卫三个参数的含义

  • to:即将进入的目标路由对象。

  • from:当前导航正要离开的路由对象。

  • next:必须调用该方法来 resolve 这个钩子。

    • next():允许导航。

    • next(false):中断当前的导航。

    • next(‘/’) 或 next({ path: ‘/’ }) 或 next(‘/new-path’):当前导航被中断,进行一个新的导航。

      注意:进行一个新的导航并不是说直接进入到了新的导航,实际上是中断了当前的导航,并重新进入路由守卫。只有遇到了 next() 才是真正的放行。

    • next(error):导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

    • next((vm) => { … }):只有 beforeRouteEnter 钩子才有。

    • next({ …to, replace: true }):重新导航到当前正要进入的路由,并且使用 replace 模式,替换当前的历史记录。

      • 例如在用户登录成功后,你可能不希望用户能通过浏览器的“返回”按钮回到登录页面。

完整的导航解析流程

  1. 导航被触发:
    用户进行了如点击链接、调用编程式导航方法(比如在 Vue Router 中使用 router.push 等)等操作,从而触发了一次新的路由导航。

  2. 在失活的组件里调用离开守卫:
    如果当前页面存在正在显示的组件(即将要离开的组件),那么会首先调用该组件内的离开守卫(例如在 Vue Router 中组件内的 beforeRouteLeave 方法)。这个守卫可以用于询问用户是否真的要离开当前页面,比如有未保存的表单数据时提示用户。

  3. 调用全局的 beforeEach 守卫:
    接着会调用全局定义的 beforeEach 守卫函数。这个守卫在每次路由导航之前都会被调用,它可以用于全局的权限验证、记录导航日志等功能。可以接受 to(即将要进入的路由)、from(当前所在的路由)和 next(用于控制导航流程的函数)作为参数。

  4. 在重用的组件里调用 beforeRouteUpdate 守卫:
    当新的导航目标与当前路由的组件是同一个(即组件被重用,比如只是路由参数发生了变化,而组件本身没有改变)时,会调用该组件内的 beforeRouteUpdate 守卫。这个守卫可以用于在组件重用时根据新的路由参数进行一些数据的更新操作。

  5. 在路由配置里调用 beforeEnter:
    对于即将要进入的路由配置中,如果定义了 beforeEnter 守卫函数,此时会调用它。beforeEnter 守卫是针对单个路由配置的,同样接受 to、from 和 next 参数,可以对特定的路由进行单独的权限或其他逻辑检查。

  6. 解析异步路由组件:
    如果即将要进入的路由对应的组件是异步加载的(比如通过 () => import('./SomeComponent.vue') 这种方式定义的异步组件),此时会开始解析并加载该异步组件。

  7. 在被激活的组件里调用 beforeRouteEnter:
    对于即将要显示的组件(即将被激活的组件),会调用其内部的 beforeRouteEnter 守卫函数。这个守卫在组件实例被创建之前调用,所以无法访问组件实例 this。它也接受 to、from 和 next 参数,并且可以通过 next 传递一个回调函数,该回调函数会在组件实例创建后被调用。

  8. 调用全局的 beforeResolve 守卫:
    在上述步骤完成后,会调用全局的 beforeResolve 守卫。这个守卫在导航被确认之前调用,主要用于确保所有的异步组件都已经解析完成,以及其他需要在导航确认前完成的操作。

  9. 导航被确认:
    经过前面一系列的守卫检查和组件解析等操作后,如果所有的 next 函数都被正确调用并且没有被阻止(例如 next(false) 会阻止导航),此时导航被确认,即将进入新的路由页面。

  10. 调用全局的 afterEach 钩子:
    导航确认后,会立即调用全局的 afterEach 钩子函数。这个钩子函数不接受 next 参数,主要用于进行一些不需要控制导航流程的操作,比如页面切换后的统计分析、更新页面标题等。

  11. 触发 DOM 更新:
    在导航确认和调用 afterEach 钩子之后,会根据新的路由渲染对应的组件,从而触发 DOM 的更新,将新的页面内容显示在浏览器中。

  12. 在创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数:
    如果在步骤 7 中 beforeRouteEnter 守卫的 next 函数传递了一个回调函数,那么在组件实例创建完成并且 DOM 更新之后,会调用这个回调函数。可以在这个回调函数中访问到已经创建好的组件实例 this,进行一些基于组件实例的初始化操作等。

route 和 router 的区别

  • this.$route 是当前路由信息对象,包括 path、params、hash、query、fullPath、matched、name 等路由信息参数

  • this.$router 是路由实例对象,包括了路由的跳转方式(push()、replace()、go())、钩子函数等

如何监听路由参数的变化

  1. watch 监听 $route 对象

    watch: {$route(to, from) {console.log(to, from)}
    }
    
  2. 调用组件内的守卫 beforeRouteUpdate

    beforeRouteUpdate(to, from, next) {console.log(to, from)next()
    }
    

创建、动态添加、删除、重置路由

Vue2

// src/router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';Vue.use(VueRouter);// 静态路由
const staticRoutes = [{path: '/login',name: 'Login',component: ()=> import(@/views/login/index)},{path: '/',name: 'Home',component: ()=> import(@/views/home/index)},{path: '/404',name: 'NotFound',component: ()=> import(@/views/error-page/index),hidden: true},
];// 创建路由
const createRouter = () => new VueRouter({mode: 'history', // history 模式// mode: 'hash', // hash 模式base: process.env.BASE_URL,routes: staticRoutes
});
const router = createRouter()// 动态路由
const dynamicRoutes = [path: '/about',name: 'About',component: ()=> import(@/views/About/index)
]// 动态添加路由,也可以在其他文件的异步方法中使用
router.addRoutes(dynamicRoutes)// 删除路由
// Vue2 没有提供删除路由的方法,只能通过重置路由的方式来间接实现删除路由。// 重置路由为初始路由
function resetRouter() {const newRouter = createRouter() // 初始路由router.matcher = newRouter.matcher; // 替换路由匹配器
}
// resetRouter(); // 需要的时候再调用// 导出路由
export default router;

Vue3

官网链接

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';// 静态路由
const staticRoutes = [{path: '/login',name: 'Login',component: () => import('@/views/login/index')},{path: '/',name: 'Home',component: () => import('@/views/home/index')},{path: '/404',name: 'NotFound',component: () => import('@/views/error-page/index'),hidden: true},
];// 创建路由
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL), // history 模式// history: createWebHashHistory(import.meta.env.BASE_URL), // hash 模式routes: staticRoutes
});// 动态路由
const dynamicRoutes = [{path: '/about',name: 'About',component: () => import('@/views/About/index')}
];// 动态添加路由
/*
注意:
Vue2 是 addRoutes,它接受一个路由数组作为参数;
Vue3 是 addRoute,一次添加一个路由。
*/
dynamicRoutes.forEach(route => {router.addRoute(route);
});// 封装 removeRoutes 方法
const removeRoutes = (routeNames) => {routeNames.forEach(name => {// 删除路由// Vue3 提供了删除单个路由的方法,参数是路由名称router.removeRoute(name);});
};
// removeRoutes(['About', 'Home']); // 移除多个路由,需要的时候再调用// 重置路由功能
function resetRouter() {// 创建一个新的路由实例const newRouter = createRouter({history: createWebHistory(process.env.BASE_URL),routes: staticRoutes // 仅包含静态路由});// 替换原有的路由实例router.matcher = newRouter.matcher;
}// 也可以通过删除所有路由来达到重置路由的目的
const removeAllRoutes = () => {// 获取所有路由名称const allRouteNames = router.getRoutes().map(route => route.name);// 遍历所有路由名称并删除对应路由allRouteNames.forEach(name => {router.removeRoute(name);});
};// 导出路由
export default router;

完整路由代码示例

import Vue from 'vue'
import Router from 'vue-router'
import store from '@/store/index'
import { getToken, removeToken } from "@/utils/index";Vue.use(Router)export const routes = [{path: '/login',component: () => import("@/views/login/index"),hidden: true},{path: '/404',component: () => import("@/views/error-page/404"),hidden: true}
]const createRouter = () => new Router({mode: "history",scrollBehavior: () => ({ y: 0 }),routes
})
const router = createRouter()
export default router/*
重写 Router 上的 push 方法,对其使用 catch 捕捉异常
*/
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push(to) {return VueRouterPush.call(this, to).catch(err => err)
}export function resetRouter() {const newRouter = createRouter()router.matcher = newRouter.matcher
}const whiteList = ['/login']router.beforeEach(async (to, from, next) => {console.log("to:",to)console.log("from:",from)const token = getToken()if (token) {if (to.path === '/login') {next({ path: '/' })} else {const routers = store.state.routersif (routers && routers.length) {// 需要添加到tags中的内容const tag = {name: to.name, url: to.path, meta: to.meta}store.commit("addTags", tag)next()} else {try {await store.dispatch("getRoutersByToken", token);next({...to,replace: true})} catch (error) {resetRouter();removeToken()store.commit('removeRouters')next('/login')}}}} else {if (whiteList.indexOf(to.path) !== -1) {next()} else {next("/login")}}
})

源码地址

源码解析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/pingmian/72239.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过mybatis的拦截器对SQL进行打标

1、背景 在我们开发的过程中&#xff0c;一般需要编写各种SQL语句&#xff0c;万一生产环境出现了慢查询&#xff0c;那么我们如何快速定位到底是程序中的那个SQL出现的问题呢&#xff1f; 2、解决方案 如果我们的数据访问层使用的是mybatis的话&#xff0c;那么我们可以通过…

【Linux】centos配置可用的yum源

在 CentOS 系统中配置可用的 YUM 源&#xff08;仓库&#xff09;是保持系统更新和软件包管理的重要步骤。下面是一些步骤和示例&#xff0c;帮助你配置可用的 YUM 源&#xff1a; 1. 备份当前 YUM 仓库配置 首先&#xff0c;备份你当前的 YUM 仓库配置文件&#xff0c;以防万…

【CentOS】搭建Radius服务器

目录 背景简介&#xff1a;Radius是什么&#xff1f;Radius服务器验证原理搭建Radius服务器环境信息yum在线安装配置FreeRADIUS相关文件clients.conf文件users文件重启服务 验证 参考链接 背景 在项目中需要用到Radius服务器作为数据库代理用户的外部验证服务器&#xff0c;做…

机器学习_特征工程

一、核心知识点&#xff1a;特征工程的核心概念与流程 1. 特征工程的定义与重要性 定义&#xff1a;通过数据预处理、特征构造、特征选择等方法&#xff0c;将原始数据转化为更适合机器学习模型输入的特征&#xff0c;提升模型性能。重要性&#xff1a; “数据和特征决定了机…

Elasticsearch Java High Level Client [7.17] 使用

es 的 HighLevelClient存在es源代码的引用&#xff0c;结合springboot使用时&#xff0c;会存在es版本的冲突&#xff0c;这里记录下解决冲突和使用方式&#xff08;es已经不建议使用这个了&#xff09;。 注意es服务端的版本需要与client的版本对齐&#xff0c;否则返回数据可…

rtsp在网页上显示(webrtc-stream)

一&#xff1a;windos 平台 1&#xff1a;下载已经编译好的windos平台程序 Releases mpromonet/webrtc-streamer (github.com) or 【免费】webrtc-streamerv0.8.6一款werbrtc服务器&#xff08;windos版本&#xff09;&#xff0c;可以直接将rtsp流拉到网页上显示资源-CSDN文…

【AI大模型智能应用】Deepseek生成测试用例

在软件开发过程中&#xff0c;测试用例的设计和编写是确保软件质量的关键。 然而&#xff0c;软件系统的复杂性不断增加&#xff0c;手动编写测试用例的工作量变得异常庞大&#xff0c;且容易出错。 DeepSeek基于人工智能和机器学习&#xff0c;它能够依据软件的需求和设计文…

如何在vscode中编译linux中的c++文件

方式一 在终端打开进行连接编译 指令含义&#xff1a;将 muduo_server.cpp 源文件编译成一个可执行文件 server&#xff0c;并且在链接过程中使用 muduo_net、muduo_base 库以及 pthread 库 方式二 在vscode中修改配置文件 按F1打开配置文件搜索栏&#xff0c;输入C/C 打开…

基于Flink SQL的实时指标多维分析模型

数据流程介绍 1.创建源表kafka接入消息队列数据&#xff0c;定义字段映射规则&#xff1b; 2.创建目标表es_sink配置Elasticsearch输出&#xff1b; 3.通过多级视图&#xff08;tmp→tmp_dedup→tmp1/tmp2→tmp3→tmp_groupby&#xff09;实现数据清洗、去重、状态计算&#x…

【vscode-01】vscode不同项目不同语言扩展插件隔离方案

vscode不同项目不同语言扩展插件隔离方案 1. 背景2. vscode 扩展插件隔离方案2.1 code-profile 配置文件2.2 配合extensions.json 1. 背景 最近打开vscode 发现越来越卡&#xff0c;这是一个轻量级代码编辑器&#xff0c;怎么会如此占用内存呢&#xff1f; 我使用了‘code --l…

《基于大数据的营养果蔬推荐系统的设计与实现》开题报告

目录 一、选题的理论意义现实意义及应用价值 &#xff08;一&#xff09;理论意义 &#xff08;二&#xff09;现实意义 1.用户价值提升 2.效率提升 3.经济效益提升 &#xff08;三&#xff09;应用价值 1.提升用户健康水平 2.优化购物体验 3.支持健康决策 4.促进农业…

《C#上位机开发从门外到门内》2-4:Modbus协议

文章目录 一、引言二、Modbus协议概述2.1 Modbus协议的起源与发展2.2 Modbus协议的基本特点2.3 应用领域 三、Modbus通信原理详解3.1 Modbus RTU原理3.1.1 数据帧结构3.1.2 数据传输与时序3.1.3 错误检测 3.2 Modbus TCP原理3.2.1 数据封装3.2.2 通信机制3.2.3 与RTU模式的区别…

观成科技:​加密C2框架Platypus流量分析

一、工具介绍 Platypus 是一款支持多会话的交互式反向 Shell 管理器。在实际的渗透测试中&#xff0c;为了解决 Netcat/Socat 等工具在文件传输、多会话管理方面的不足,该工具在多会话管理的基础上增加了在渗透测试中能更好发挥作用的功能&#xff08;如&#xff1a;交互式 Sh…

OpenBMC:BmcWeb 处理http请求

OpenBMC:BmcWeb 读取http请求头-CSDN博客 介绍了,在读取完http头后,将调用Connection::handle处理http请求 1.Connection::handle void handle() {...req = std::make_shared<crow::Request>(parser->release(), reqEc);...req->session = userSession;accept …

MySQL事务深度解析:ACID特性、隔离级别与MVCC机制

引言 在数据库系统中&#xff0c;​事务是保障数据一致性与完整性的核心机制。MySQL通过ACID特性、多级隔离策略和MVCC&#xff08;多版本并发控制&#xff09;实现了高性能与高可靠性的平衡。本文将从底层原理出发&#xff0c;系统解析事务的四大特性、隔离级别的实现逻辑&am…

WireShark自动抓包

背景 异常流量检测是当前保护网络空间安全的重要检测方法。 对流量的研究&#xff0c;首先需要在系统中进行抓包&#xff0c;并对包进行分析。 这里对WireShark自动抓包进行简要介绍。 操作步骤 1、选择“捕获”>“选项”。 2、在Input下&#xff0c;选择要抓包的网络接…

Android 自定义View之底部导航栏

文章目录 Android 自定义View之底部导航栏概述代码定义TabIndex定义Tab定义TabView定义NavigationBarFragmentSwitchHelper管理类使用 源码下载 Android 自定义View之底部导航栏 概述 封装一个通用的底部导航栏控件。 代码 定义TabIndex Retention(AnnotationRetention.SOU…

西门子S7-1200 PLC远程调试技术方案(巨控GRM532模块)

三步快速实现远程调试 硬件部署 准备西门子S7-1200 PLC、巨控GRM552YW-C模块及编程电脑。GRM552YW-C通过网口与PLC连接&#xff0c;支持4G/5G/Wi-Fi/有线网络接入&#xff0c;无需复杂布线。 软件配置 安装GVCOM3配置软件&#xff0c;注册模块&#xff08;输入唯一序列号与密…

上下文学习思维链COTPrompt工程

一、上下文学习 上下文学习强调在学习过程中考虑问题所处的上下文环境。 1.1 上下文学习的分类 零样本&#xff08;Zero-Shot&#xff09;上下文学习单样本&#xff08;One-Shot&#xff09;上下文学习少样本&#xff08;Few-Shot&#xff09;上下文学习 1.2 示例选择方法 …

node.js-WebScoket心跳机制(服务器定时发送数据,检测连接状态,重连)

1.WebScoket心跳机制是&#xff1f; 基于上一篇文章&#xff0c;WebScoket在浏览器和服务器间完成一次握手&#xff0c;两者间创建持久性连接&#xff0c;并进行双向数据连接。node.js-node.js作为服务器&#xff0c;前端使用WebSocket&#xff08;单个TCP连接上进行全双工通讯…