vue-router(動態路由,嵌套式路由,編程式路由)
本文是基於官網學習,官網具體學習目錄:vue-router
一、安裝
基於vue-cli腳手架安裝還是蠻簡單的:在文件當前目錄下運行:
npm install vue-router
如果在一個模塊化工程中使用它,必須要通過 Vue.use()
明確地安裝路由功能:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)
腳手架安裝教程: 腳手架安裝教程
其他類型安裝詳見官網:安裝
二、單頁面應用
官網介紹的已經很全面。
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <h1>Hello App!</h1> <p> <!-- 使用 router-link 組件來導航. --> <!-- 通過傳入 `to` 屬性指定鏈接. --> <!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 --> <router-link to="/foo">Go to Foo</router-link> <router-link to="/bar">Go to Bar</router-link> </p> <!-- 路由出口 --> <!-- 路由匹配到的組件將渲染在這里 --> <router-view></router-view> </div> <script> // 0. 如果使用模塊化機制編程,導入Vue和VueRouter,要調用 Vue.use(VueRouter) // 1. 定義(路由)組件。 // 可以從其他文件 import 進來 const Foo = { template: '<div>foo</div>' } const Bar = { template: '<div>bar</div>' } // 2. 定義路由 // 每個路由應該映射一個組件。 其中"component" 可以是 // 通過 Vue.extend() 創建的組件構造器, // 或者,只是一個組件配置對象。 // 我們晚點再討論嵌套路由。 const routes = [{ path: '/foo', component: Foo }, { path: '/bar', component: Bar }] // 3. 創建 router 實例,然后傳 `routes` 配置 // 你還可以傳別的配置參數, 不過先這么簡單着吧。 const router = new VueRouter({ routes // (縮寫)相當於 routes: routes }) // 4. 創建和掛載根實例。 // 記得要通過 router 配置參數注入路由, // 從而讓整個應用都有路由功能 const app = new Vue({ router }).$mount('#app') // 現在,應用已經啟動了! </script> <!-- 要注意,當 <router-link> 對應的路由匹配成功,將自動設置 class 屬性值 .router-link-active --> <style> .router-link-active { color: red; } </style>
效果:
這個案例,就是不同路徑顯示不同組件。
三、動態路由匹配
我們經常需要把某種模式匹配到的所有路由,全都映射到同個組件。比如/user/name、/user/age、/user/haha都要映射到user組件,怎么做呢?
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <p> <router-link to="/user/foo">/user/foo</router-link> <router-link to="/user/bar">/user/bar</router-link> </p> <router-view></router-view> </div> <script> //一個『路徑參數』使用冒號 : 標記。當匹配到一個路由時, //參數值會被設置到 this.$route.params,可以在每個組件內使用。於是,我們可以更新 User 的模板 //輸出當前用戶的 ID const User = { template: `<div>User {{ $route.params.id }}</div>` } // 動態路徑參數 以冒號開頭 //現在呢,像 /user/foo 和 /user/bar 都將映射到相同的路由。 const router = new VueRouter({ routes: [{ path: '/user/:id', component: User }] }) const app = new Vue({ router }).$mount('#app') </script> <style> .router-link-active { color: red; } </style>
效果:
你可以在一個路由中設置多段『路徑參數』,對應的值都會設置到 $route.params
中。例如:
模式 | 匹配路徑 | $route.params | |
---|---|---|---|
/user/:username | /user/evan | { username: 'evan' } |
|
/user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: 123 } |
四、嵌套路由
嵌套路由是個常見的需求,假設用戶能夠通過路徑/home/news
和/home/message
訪問一些內容,一個路徑映射一個組件,訪問這兩個路徑也會分別渲染兩個組件。
實現嵌套路由有兩個要點:
- 在組件內部使用
<router-view>
標簽 VueRouter
的參數中使用children
配置
<div id="app"> <router-view></router-view> </div>
這里的 <router-view>
是最頂層的出口,渲染最高級路由匹配到的組件。同樣地,一個被渲染組件同樣可以包含自己的嵌套 <router-view>
。例如,在 User
組件的模板添加一個 <router-view>
const User = { template: ` <div class="user"> <h2>User {{ $route.params.id }}</h2> <router-view></router-view> </div> ` }
要在嵌套的出口中渲染組件,需要在 VueRouter
的參數中使用 children
配置
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 當 /user/:id/profile 匹配成功, // UserProfile 會被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 當 /user/:id/posts 匹配成功 // UserPosts 會被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
要注意,以 /
開頭的嵌套路徑會被當作根路徑。 這讓你充分的使用嵌套組件而無須設置嵌套的路徑。
此時,基於上面的配置,當你訪問 /user/foo
時,User
的出口是不會渲染任何東西,這是因為沒有匹配到合適的子路由。如果你想要渲染點什么,可以提供一個 空的 子路由:
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ // 當 /user/:id 匹配成功, // UserHome 會被渲染在 User 的 <router-view> 中 { path: '', component: UserHome }, // ...其他子路由 ] } ] })
綜合小案例:
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <p> <router-link to="/user/foo">/user/foo</router-link> <router-link to="/user/foo/profile">/user/foo/profile</router-link> <router-link to="/user/foo/posts">/user/foo/posts</router-link> </p> <router-view></router-view> </div> <script> const User = { template: ` <div class="user"> <h2>User {{ $route.params.id }}</h2> <router-view></router-view> </div> ` } const UserHome = { template: '<div>Home</div>' } const UserProfile = { template: '<div>Profile</div>' } const UserPosts = { template: '<div>Posts</div>' } const router = new VueRouter({ routes: [{ path: '/user/:id', component: User, children: [{ // /user/:id/匹配到UserHome組件,如果你是/user/:id/home是匹配不到任何組件的,因為children里沒有home路徑 path: '', component: UserHome }, { // /user/:id/profile匹配到UserProfile組件 path: 'profile', component: UserProfile }, { // /user/:id/posts匹配到UserPosts組件 path: 'posts', component: UserPosts } ] }] }) const app = new Vue({ router }).$mount('#app') </Script>
效果:
五、編程式路由
1、router.push
上面幾種路由都是直接在頁面點擊進行跳轉,但在我們實際開發過程中,有很多按鈕在執行跳轉之前,還會執行一系列方法,這時可以使用 this.$router.push(location) 來修改 url,完成跳轉
想要導航到不同的 URL,則使用 router.push
方法。這個方法會向 history 棧添加一個新的記錄,所以,當用戶點擊瀏覽器后退按鈕時,則回到之前的 URL。
當你點擊 <router-link>
時,這個方法會在內部調用,所以說,點擊 <router-link :to="...">
等同於調用 router.push(...)
。
聲明式 | 編程式 |
---|---|
<router-link :to="..."> |
router.push(...) |
該方法的參數可以是一個字符串路徑,或者一個描述地址的對象。例如:
// 字符串 router.push('home') // 對象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 帶查詢參數,變成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path
,params
會被忽略,上述例子中的 query
並不屬於這種情況。取而代之的是下面例子的做法,你需要提供路由的 name
或手寫完整的帶有參數的 path
const userId = 123 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 這里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
同樣的規則也適用於 router-link
組件的 to
屬性。
2.router.replace
跟 router.push
很像,唯一的不同就是,它不會向 history 添加新記錄,而是跟它的方法名一樣 —— 替換掉當前的 history 記錄。(下面會具體說明)
聲明式 | 編程式 |
---|---|
<router-link :to="..." replace> |
router.replace(...) |
3、router.go(n)
這個方法的參數是一個整數,意思是在 history 記錄中向前或者后退多少步,類似 window.history.go(n)
。
// 在瀏覽器記錄中前進一步,等同於 history.forward() router.go(1) // 后退一步記錄,等同於 history.back() router.go(-1) // 前進 3 步記錄 router.go(3) // 如果 history 記錄不夠用,那就默默地失敗唄 router.go(-100) router.go(100)
4、三個比較說明:
1.this.$router.push():
跳轉到不同的url,但這個方法回向history棧添加一個記錄,點擊后退會返回到上一個頁面。
2.this.$router.replace()
同樣是跳轉到指定的url,但是這個方法不會向history里面添加新的記錄,點擊返回,會跳轉到上上一個頁面。上一個記錄是不存在的。
3.this.$router.go(n)
相對於當前頁面向前或向后跳轉多少個頁面,類似 window.history.go(n)
。n可為正數可為負數。正數返回上一個頁面
4、在什么情況用push,或者在上面情況用replace,個人理解:
一般情況下,要做前進后退的瀏覽記錄管理的,基本上都是用router.push()
,但是也是有一些特殊情況需要用到router.replace()
。比如,有一個授權頁,用戶在按流程操作時,某一步需要授權,是直接跳到授權頁,授權頁提交授權請求,直到成功授權后,跳到流程中的下一步操作的地址。此處,授權請求的那頁面應該用replace
去替換掉自身的訪問記錄,防止用戶跳到下一步流程后按后退鍵回退到授權頁,而導致重復授權,簡單來講就是你跳過來了,就不讓你后退又到上一個頁面。
舉例:
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <button type="button" @click="fooClick">/user/foo</button> <button type="button" @click="profileClick">/user/foo/profile</button> <button type="button" @click="postsClick">/user/foo/posts</button> <router-view></router-view> </div> <script> //定義了三個組件 const UserHome = { template: '<div>Home</div>' } const UserProfile = { template: '<div>Profile</div>'} const UserPosts = { template: '<div>Posts</div>' } //匹配了三個路由 const router = new VueRouter({ routes: [{ path: '/user/foo', component: UserHome, }, { path: '/user/foo/profile', component: UserProfile, }, { path: '/user/foo/posts', component: UserPosts, }] }) const app = new Vue({ el: '#app', router, data: { foo: '/user/foo', profile: '/user/foo/profile', posts: '/user/foo/posts' }, methods: { fooClick: function(event) { this.$router.push({ path: this.foo }); }, profileClick: function(event) { this.$router.push({ path: this.profile }); }, postsClick: function(event) { this.$router.push({ path: this.posts }); } } }) </Script>
頁面:
測試結果:當使用 this.$router.push,時,前進一步后退一步都會退到上一次進入的頁面,而使用 this.$router.replace並不不會調到上一個頁面。
想太多,做太少,中間的落差就是煩惱。想沒有煩惱,要么別想,要么多做。中尉【19】