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 守衛是針對單個路由配置的,同樣接受 tofromnext 參數,可以對特定的路由進行單獨的權限或其他邏輯檢查。

  6. 解析異步路由組件
    如果即將要進入的路由對應的組件是異步加載的(比如通過 () => import('./SomeComponent.vue') 這種方式定義的異步組件),此時會開始解析并加載該異步組件。

  7. 在被激活的組件里調用 beforeRouteEnter
    對于即將要顯示的組件(即將被激活的組件),會調用其內部的 beforeRouteEnter 守衛函數。這個守衛在組件實例被創建之前調用,所以無法訪問組件實例 this。它也接受 tofromnext 參數,并且可以通過 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.pswp.cn/pingmian/72239.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72239.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72239.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋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連接上進行全雙工通訊…