2021-05-12 14:32:11
在nuxt中使用路由重定向的範例
我們都知道,在寫SPA的時候,我們可以通過設定vue-router來實現路由的重定向。
官方檔案(以及ts型別)的定義中給出了這一選項:
interface RouteConfig = { path: string, redirect?: string | Location | Function, }
也就是說,我們可以定義這樣一個路由:
{ path: "/foo", redirect: "/foo/bar", }
這樣,我們在存取/foo的時候,就會被重定向到/foo/bar。這些都是老生常談了。
然而,到了SSR的環境下,如果使用nuxt,因為nuxt採用了約定大於設定的方式,pages目錄代替了路由,雖然簡化了設定,但是給一些需要客製化化的場景的手動設定帶來了一些麻煩,並且nuxt官方也不建議手動設定router,如果實在需要設定,可以在nuxt.config.js裡進行一些中介軟體設定,但是這個對於重定向這種特別簡單的事情來說,未免有殺雞用牛刀之嫌。
所以,我一開始想的辦法是,在pages目錄下,需要重定向的路由元件裡,增加一個beforeCreate()勾點:
<template> <div></div> </template> <script> export default { beforeCreate() { this.$router.replace('/path/to') } } </script>
相當於在元件建立之前進行一個路由的替換,這個元件作為路由的佔位。之所以不用push而是用replace,因為replace更接近重定向的效果,我們總不希望使用者還能回退(比如瀏覽器的後退鍵)到重定向之前的頁面裡去吧。
但是這個方案有一個問題,就是在路由「重定向」的過程中,介面會發生輕微的閃爍,這樣體驗就很不好了。所以,肯定需要其他的解決方案。
至於為什麼會閃屏,因為雖然beforeCreate勾點理論上會先於模板編譯執行,但是這是在SFC環境下,模板編譯會提前執行;如果是用script標籤引入的Vue就不會有這個問題:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script> <script src="https://unpkg.com/vue-router@3.1.6/dist/vue-router.js"></script> </head> <body> <div id="app"> <router-view/> </div> <script> const Foo = {template: '<div>foo</div>'}; const Bar = {template: '<div>bar</div>'}; const routes = [ {path: '/foo', component: Foo, redirect: '/bar'}, {path: '/bar', component: Bar} ]; const router = new VueRouter({routes}); const app = new Vue({ el: '#app', router }) </script> </body> </html>
如果有需要,可以進一步參考Vue官方的生命週期圖示。
查了一下檔案,好在nuxt提供了這麼一個重定向的API,就藏在context物件裡。事實上,下面所有的解決方案,都是基於這個context物件進行的:
屬性欄位 | 型別 | 可用 | 描述 |
---|---|---|---|
redirect | Function | 使用者端 & 伺服器端 | 用這個方法重定向使用者請求到另一個路由。狀態碼在伺服器端被使用,預設 302 redirect([status,] path [, query]) |
同時,我們還知道:
asyncData方法會在元件(限於頁面元件)每次載入之前被呼叫。它可以在伺服器端或路由更新之前被呼叫。在這個方法被呼叫的時候,第一個引數被設定為當前頁面的上下文物件,你可以利用 asyncData方法來獲取資料並返回給當前元件。
所以,我們可以這麼寫:
<template> <div></div> </template> <script> export default { asyncData({ redirect }) { redirect('/path/to') } } </script>
這樣就可以解決問題了。可能你會想為什麼不用fetch來進行路由跳轉,因為fetch是用來處理vuex store的資料的,我個人認為從語意上不適合處理路由跳轉的任務;當然,實際上是可以正常執行的,反正都是基於context物件進行的操作。
如果你對上面那個空的div感到不滿意,覺得不優雅,你也可以搞得更極端一點,使用渲染函數來渲染模板的根節點:
<script> export default { asyncData({ redirect }) { redirect('/path/to') }, render(h) { return h('div') } } </script>
這樣看起來可能更簡潔一點。
但是這種寫法對於路由鑑權那種場景是不太適用的。比如,我需要在進行路由跳轉前驗證使用者的身份,我總不能在每個page裡都寫這麼一段吧,維護起來也不方便,如果路由改了,每個頁面都得改。
所以,這個時候就得用到nuxt提供的中介軟體機制了。中介軟體可以在page層面設定,也可以全域性設定,參考官方的例子:
pages/secret.vue
<template> <h1>Secret page</h1> </template> <script> export default { middleware: 'authenticated' } </script>
middleware/authenticated.js
export default function ({ store, redirect }) { // If the user is not authenticated if (!store.state.authenticated) { return redirect('/login') } }
這個也放到nuxt.config.js裡,變成全域性的設定:
module.exports = { router: { middleware: 'authenticated' } }
但是有一點需要注意,也是隻要使用路由就需要注意的一個問題:避免迴圈重定向。這和避免寫死迴圈是一個道理。
總結一下:
如果是少數幾個頁面之間的固定的重定向邏輯,可以直接用asyncData(或者fetch,雖然我個人覺得語意不好)引數裡context的redirect來進行重定向;
如果需要重定向的頁面數量較多(可以考慮使用中介軟體 + 表驅動),或者存在一些動態變化的重定向邏輯(比如路由鑑權),可以考慮使用中介軟體機制。
補充知識:使用Nuxt.js和Vue-i18n重定向到同一頁面但切換語言URL
公司最近提出一個需求,就是當用戶切換語言的時候,在路由中需要將其選中的語言加入到路由中
例如網址:
localhost/about
應該通過該方法(通過按特定按鈕)重定向到:
localhost/bg/about
Nuxt檔案中所建議的,用於使用Vue-i18n進行在地化https://nuxtjs.org/examples/i18n/
在 Nuxt 官網中也給出了國際化的例子,但是並不滿足公司的這個需求,大家有興趣可以去看下
Nuxt 官網 國際化的例子
在 components資料夾下面新建 LangSelect.vue檔案
<template> <el-dropdown trigger="click" class="international" @command="handleSetLanguage"> <div> <i class="el-icon-share">{{$t('home.changelang')}}</i> </div> <el-dropdown-menu slot="dropdown"> <el-dropdown-item :disabled="language==='zh'" command="zh">中文</el-dropdown-item> <el-dropdown-item :disabled="language==='en'" command="en">English</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </template> <script> export default { computed: { language() { return this.$store.state.locale; } }, methods: { handleSetLanguage(language) { this.$i18n.locale = language; console.log(this.$i18n.locale); this.$store.commit("SET_LANG", language); // console.log(this.$store.state.locale, "locale"); var beforePath = this.$nuxt.$router.history.current.path; // -- Removing the previous locale from the url var changePath = this.$store.state.locale var result = ""; result = beforePath.replace("/en", ""); result = result.replace("/zh", ""); this.$nuxt.$router.replace({ path: "/" + changePath + result }); this.$message({ message: "Switch Language Success", type: "success" }); } } }; </script>
在middleware檔案中新建i18n.js
export default function ({ isHMR, app, store, route, params, error, redirect }) { const defaultLocale = app.i18n.fallbackLocale // If middleware is called from hot module replacement, ignore it //如果從熱模組替換呼叫中介軟體,請忽略它 if (isHMR) { return } // Get locale from params const locale = params.lang || defaultLocale if (!store.state.locales.includes(locale)) { return error({ message: 'This page could not be found.', statusCode: 404 }) } // Set locale store.commit('SET_LANG', locale) app.i18n.locale = store.state.locale if(route.fullPath == '/') { return redirect('/' + defaultLocale + '' + route.fullPath) } }
其他的設定都可以在 上面給出的官網連結中找到,這裡就不在重複了。
以上這篇在nuxt中使用路由重定向的範例就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章