Vue-router學習筆記

那這次呢?我決定直接就先放一個小小demo上來

<body>
    <div id="app">
        <router-link to="/user">user</router-link>
        <router-link to="/about">about</router-link>

        <!-- 匹配到的路由組件都放在這里 -->
        <router-view></router-view>
    </div>
    <script src="../lib/vue.js"></script>
    <script src="../lib/vue-router.js"></script>
    <script>

        //定義組件模板
        const User = { template: '<h1>user</h1>' }
        const About = { template: '<h1>about</h1>' }

        // 定義路由配置
        const routes = [
            { path: "/user", component: User },
            { path: "/about", component: About },
        ]

        // 初始化路由
        const router = new VueRouter({
            routes
        })

        // 使用路由
        new Vue({
            router
            ,mounted() {
                // 訪問路由器也就是VueRouter實例
                console.log(this.$router);
                // 訪問當前的路由信息
                console.log(this.$route);
            },
        }).$mount("#app");
    </script>
</body>

其實我們在引入vue-router插件那一刻,我們的網頁就已經附帶上hash路由了,哪怕什么都沒有做


那么你打開這個demo就會發現url最后加上了#/hash路由的標記了,然后我們通過router-lInk標簽跳轉路由(其實a標簽也行,但是a標簽必須要寫出相對完整的URL)這樣一個簡單的vue-router就實現了

路由傳參

params傳參

        <router-link to="/user/小鋼炮">小鋼炮</router-link>
        <router-link to="/user/大鋼炮">大鋼炮</router-link>
        <!-- 如果未匹配到params參數就為空 -->
        <router-link to="/user">我是哪個</router-link>

        //打印接收到的參數
        const User = { template: '<h1>{{this.$route.params.id}}</h1>' }

        // 定義路由配置
        const routes = [
            // 通過:屬性名的方式指定接收參數的名字
            { path: "/user/:id", component: User },
        ]

path匹配url可以使用正則

        <router-link to="/user-小鋼炮">小鋼炮</router-link>
        <router-link to="/user-大鋼炮">大鋼炮</router-link>
        <!-- 如果未匹配到params參數就為空 -->
        <router-link to="/user-">我是哪個</router-link>


        //使用通配符,組件中會有一個params對象中有一個pathMatch值,代表通配符匹配到的內容
        const User = { template: '<h1>我匹配到了 {{$route.params.pathMatch}}</h1>' }

        const routes = [
            // 匹配所有user-開頭的路由
            { path: "/user-*", component: User },

            // 所以我這里就可以匹配所有的路由,但是這個匹配規則必須放在最后面
            // 因為vue-router是從前到后一次匹配的,這個可以做一個默認的無匹配路由的404組件
            // {path:"*",component:main}
        ]

嵌套路由

<body>
    <div id="app">
        <!-- 我這里定義了一個跳轉層級的標簽 -->
        <router-link to="/user">user界面</router-link>
        <!-- 匹配到的路由組件都放在這里 -->
        <router-view></router-view>
    </div>
    <template id="user">
        <div>
            <h1>user組件</h1>
            <router-link to="/user/大鋼炮">大鋼炮</router-link>

            <!-- 每一個組件中還有子路由必須要加router-view組件 -->
            <router-view></router-view>
        </div>
    </template>
    <template id="DaPao">
        <div>
            <h2>大鋼炮</h2>
            <router-link to="/user/大鋼炮/小鋼炮">小鋼炮</router-link>
            <!-- 每一個組件中還有子路由必須要加router-view組件 -->
            <router-view></router-view>
        </div>
    </template>
    <template id="XiaoPao">
        <div>
            <h3>我是大鋼炮的兒子小鋼炮 --->> 8888</h3>
        </div>
    </template>
    <script src="../lib/vue.js"></script>
    <script src="../lib/vue-router.js"></script>
    <script>

        const User = { template: "#user" }
        const DaPao = { template: "#DaPao" }
        const XiaoPao = { template: "#XiaoPao" }

        const routes = [
            {
                path: "/user", component: User,
                // 每一個匹配規則都有一個children屬性,就跟routes一樣的配置,里面配置對應規則中的子路由
                children: [
                    // 不要寫 / ,不然就是匹配跟路由了,vue會自動轉換為/user/大鋼炮的
                    {
                        path: "大鋼炮", component: DaPao,
                        // 理論上來說是可以無限嵌套的
                        children: [
                            { path: "小鋼炮", component: XiaoPao }
                        ]
                    }
                ]
            },
        ]

        // 初始化路由
        const router = new VueRouter({
            routes
        })

        // 使用路由
        new Vue({
            router
        }).$mount("#app");
    </script>
</body>
image.png
<body>
    <div id="app">
        <!-- 我這里定義了一個跳轉層級的標簽 -->
        <router-link to="/user/xiaoming">小明</router-link>
        <router-link to="/user/xiaoming/xiaoming">真小明</router-link>
        <!-- 匹配到的路由組件都放在這里 -->
        <router-view></router-view>
    </div>
    <template id="user">
        <div>
            <h1>user組件</h1>
            <router-link to="/user/大鋼炮">大鋼炮</router-link>
            {{$route.params.id}}
            <!-- 每一個組件中還有子路由必須要加router-view組件 -->
            <router-view></router-view>
        </div>
    </template>
    <template id="DaPao">
        <div>
            {{$route.params.id}}
        </div>
    </template>
    <template id="XiaoPao">
        <div>
            <h3>我是大鋼炮的兒子小鋼炮 --->> 8888</h3>
        </div>
    </template>
    <script src="../lib/vue.js"></script>
    <script src="../lib/vue-router.js"></script>
    <script>

        const User = { template: "#user" }
        const DaPao = { template: "#DaPao" }
        const XiaoPao = { template: "#XiaoPao" }

        const routes = [
            {
                // 這樣的子路由匹配的啥呢
                path: "/user/:id", component: User,
                children: [
                    // 匹配的是/user/:id/xiaoming
                    {path:"xiaoming",component:DaPao},
                    // 如果希望/user/:id匹配到了想顯示一些東西可以這樣,path留空字符串
                    // /user/:id 
                    {path:"",component:XiaoPao}
                ]
            },
        ]

        // 初始化路由
        const router = new VueRouter({
            routes
        })

        // 使用路由
        new Vue({
            router
        }).$mount("#app");
    </script>
</body>

編程式導航

除了使用 <router-link> 創建 a 標簽來定義導航鏈接,我們還可以借助 router 的實例方法,通過編寫代碼來實現。

  • router.push(location, onComplete?, onAbort?)

注意:在 Vue 實例內部,你可以通過 $router 訪問路由實例。因此你可以調用 this.$router.push。當你點擊 <router-link> 時,這個方法會在內部調用,所以說,點擊 <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.2.0+,可選的在 router.push 或 router.replace 中提供 onComplete 和 onAbort 回調作為第二個和第三個參數。這些回調將會在導航成功完成 (在所有的異步鉤子被解析之后) 或終止 (導航到相同的路由、或在當前導航完成之前導航到另一個不同的路由) 的時候進行相應的調用。
注意: 如果目的地和當前路由相同,只有參數發生了改變 (比如從一個用戶資料到另一個 /users/1 -> /users/2),你需要使用 beforeRouteUpdate來響應這個變化 (比如抓取用戶信息)。

  • router.replace(location, onComplete?, onAbort?)

跟 router.push 很像,唯一的不同就是,它不會向 history 添加新記錄,而是跟它的方法名一樣 —— 替換掉當前的 history 記錄。

  • 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)

你也許注意到 router.push、 router.replacerouter.gowindow.history.pushStatewindow.history.replaceStatewindow.history.go好像, 實際上它們確實是效仿 window.history API 的。
因此,如果你已經熟悉 Browser History APIs,那么在 Vue Router 中操作 history 就是超級簡單的。
還有值得提及的,Vue Router 的導航方法 (push、 replace、 go) 在各類路由模式 (history、 hashabstract) 下表現一致。

命名路由

有時候,通過一個名稱來標識一個路由顯得更方便一些,特別是在鏈接一個路由,或者是執行一些跳轉的時候。你可以在創建 Router 實例的時候,在 routes 配置中給某個路由設置名稱。

const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
      name: 'user',
      component: User
    }
  ]
})

要鏈接到一個命名路由,可以給 router-link 的 to 屬性傳一個對象:

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

這跟代碼調用 router.push() 是一回事:

// params傳參必須使用命名路由或者直接手寫path
// path :"/user/"+this.msg --> `/user/${this.msg}`
router.push({ name: 'user', params: { userId: 123 }})

這兩種方式都會把路由導航到 /user/123 路徑。

命名視圖

有時候想同時 (同級) 展示多個視圖,而不是嵌套展示,例如創建一個布局,有 sidebar (側導航) 和 main (主內容) 兩個視圖,這個時候命名視圖就派上用場了

<router-view name="nav"></router-view>

router-view組件提供了一個name屬性,根據name屬性的不同允許同層級(同路由情況下)存在多個不同的組件,默認不加name的router-view默認的name就是default很想插槽的name

        <!-- 每一個組件中還有子路由必須要加router-view組件 -->
        <router-view name="DaPao"></router-view>
        <router-view name="XiaoPao"></router-view>
        <router-view></router-view>


        const User = { template: "#user" }
        const DaPao = { template: "#DaPao" }
        const XiaoPao = { template: "#XiaoPao" }

        const routes = [
            {
                path: "/",
                // 同時顯示多個組件使用components
                components: {
                    default: User,
                    DaPao, XiaoPao
                }
            },
        ]

嵌套命名視圖

<body>
    <div id="app">
        <router-link to="/user/about">關于</router-link>
        <router-link to="/user/info">資料</router-link>
        <!-- 默認router坑 -->
        <router-view></router-view>
    </div>
    <script src="../lib/vue.js"></script>
    <script src="../lib/vue-router.js"></script>
    <script>

        const About = {
            template: `
            <h3> \
                About組件 \
            </h3> \
            `
        }

        const User = {
            template: `
                <h2> \
                    這是用戶組件 \
                    <router-view></router-view>
                    <router-view name="profile"></router-view>
                </h2> \
            `
        }

        const Profile = {
            template:`
                <h1> \
                    Profile組件,嵌套視圖組件 \
                </h1> \
            `
        }

        const Info = {
            template:`
            <h1> \
                Info組件 \
            </h1>
            `
        }

        const routes = [

// 默認的根 / 會被重定向到/user路由下
            { path: "/", redirect: "/user" },

            {
                path: "/user", component: User, children: [
                    {path:"about",component:About},
                    // 嵌套視圖組件
                    {path:"info",components:{
                        default:Info,
                        profile:Profile
                    }}
                ]
            }
        ]

        // 初始化路由
        const router = new VueRouter({
            routes
        })

        // 使用路由
        new Vue({
            router
        }).$mount("#app");
    </script>
</body>

重定向和別名

// 默認的根 / 會被重定向到/user路由下
{ path: "/", redirect: "/user" },
// 重定向也可以是一個對象
 { path: "/", redirect: {path:'/user'} },
//甚至是一個方法,動態返回重定向目標:
{ path: "/", redirect: to =>{
// to為一個目標路由信息
// return 重定向的 字符串路徑/路徑對象
       return '/user'
} },

別名


image.png

image.png

聲明了別名的路由,就像上面這個例子,你其實顯示的是訪問/you,其實里面還是渲染的/user的內容,雖然你訪問的/you但是實際上返回的確實/user的內容

路由組件傳參

在組件中使用 $route 會使之與其對應路由形成高度耦合,從而使組件只能在某些特定的 URL 上使用,限制了其靈活性。

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})
const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },

    // 對于包含命名視圖的路由,你必須分別為每個命名視圖添加 `props` 選項:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
})

props的幾種類型

  • 布爾類型
        const routes = [
            // props為bool值,為真代表會將params設置為組件的屬性(根元素)
            // 這里就是 ---> name === 匹配到的value
            { path: "/user/:name", component: User, props: true }
        ]
  • 對象模式
        const routes = [
            // 如果props為對象,那么里面的鍵值對就會對應html元素中的屬性進行設置
            { path: "/user/:name", component: User, props:{name:"suiyue"}}
        ]
  • 函數模式
        const routes = [
            // 如果props為函數有一個可選的屬性route,代表當前的路由信息
            // 這樣你便可以將參數轉換成另一種類型,將靜態值與基于路由的值結合等等。
            { path: "/user/:name", component: User, props:(route)=>({name:route.params.name})}
        ]

HTML5History模式

vue路由默認是hash模式,這種url感覺上不是那么的棒,所以vue可以使用html5支持的history模式,這種模式路由的URL更接近正常的URL,但是由于跟正常的URL很像所以每一個請求都將真實發出,所以服務端需要配置一個用于所有404的index.html頁面,部分服務端配置例子

因為這樣的話就會出現一種情況就是,頁面不會出現404界面了,但是還記得之前說的通配符嗎?我們可以直接將一個path匹配通配符的匹配規則放在最后面,這樣的話就可以模擬出一個404界面了

image.png

進階

導航守衛

說白了就是不同時期觸發的鉤子函數而已

  • 全局前置守衛

        // 全局前置守衛
        router.beforeEach((to, from, next) => {
            // to與from看下面
            /* 
                next函數不僅可以通過調用繼續路由
                還可以改變路由的目標指向
                next()  --> 繼續路由
                next(false)   --> 取消路由 | 也可以直接不調用
                // 同樣可以改變路由的指向,對象參數如router.push函數
                next('/suiyue') or next({name:'user',params:{}})  
                next(error) --> (2.4+)  如果傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 注冊過的回調。
             */

             /* 
一個坑
                直接調用next()函數的回調地獄
                當你直接調用next()函數重定向一個路由的時候
                比如說
                next('/user') 重定向到/user路由,那么這些鉤子函數還會進行執行一次
                就是加入這在這個鉤子函數中使用了 next('/suiyue') 跳轉到/suiyue路由
                那么這個next函數一執行,立馬又會重新執行鉤子函數,所以又會重新進入這個函數
                然后又執行到next('/suiyue')然后又進行執行,這樣最后就會造成堆棧溢出錯誤了
                大家可以直接在這個函數試試,所以next重定向路由的時候一定要進行一個判斷
              */
        })
  • 全局解析守衛

在 2.5.0+ 你可以用 router.beforeResolve 注冊一個全局守衛。這和 router.beforeEach 類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被調用。

        // router就是vue-router實例
        router.beforeResolve((to, from, next) => {
            // 將要前往的路由
            console.log(to);
            // 從哪個路由跳轉到這個路由
            console.log(from);

            setTimeout(()=>{
                // 什么時候調用next什么時候繼續解析路由
                // 不調用將不會繼續解析路由,相當于路由失敗不會顯示對應的組件
                next();
            },1000);
        })
  • 全局后置鉤子
        // 全局后置鉤子
        router.afterEach((to, from) => {
            // 這兩個參數跟全局解析守衛一樣
            // 如果前面有任何守衛(全局的或者局部的)沒有調用next()將不會執行此鉤子函數
            console.log(to);
            console.log(from);
        })

守衛和鉤子最大的不同在于,守衛有一個next回調函數,可以通過函數中的邏輯控制路由是否能夠達到預期而選擇是否繼續路由,而鉤子函數就不會影響路由本身,適合只用于處理邏輯

  • 路由獨享守衛
        const routes = [
            {
                path: "/user/:name", component: User,
                // 路由獨享守衛
                beforeEnter: (to, from, next) => {
                    next();
                }
            },
        ]

就記住了這么一句話,所有守衛就這么固定三個參數,所有鉤子函數就沒有next參數

  • 組件內的守衛

注釋已經寫得很詳細了

        const User = {
            template: `
            <h1>
                我是{{$route.params.id}}
            </h1>
            `,
            /* 
                組件內的守衛,就是在路由到對應組件的時候誰調用
                直白一點就是,這個路由那個組件顯示就調用哪個組件的
                鉤子函數
             */
            beforeRouteEnter(to, from, next) {
                // 在渲染該組件的對應路由被 confirm 前調用
                // 不!能!獲取組件實例 `this`
                // 因為當守衛執行前,組件實例還沒被創建

                // 因為此守衛無法訪問組件的實例,所以可以可選的給next傳入一個回調,Vue會將對應組件的實例傳到回調的第一個參數
                next(vm =>{
                    // vm就是對應組件的實例
                    // 此鉤子函數是唯一一個支持next傳回調的鉤子,因為這個鉤子函數無法獲取組件的實例,所以需要這么做
                    console.log(vm);
                });
            },
            // 2.2+
            beforeRouteUpdate(to, from, next) {
                // 在當前路由改變,但是該組件被復用時調用
                // 舉例來說,對于一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
                // 由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。
                // 可以訪問組件實例 `this`
                next();
            },
            beforeRouteLeave(to, from, next) {
                // 導航離開該組件的對應路由時調用
                // 可以訪問組件實例 `this`


                // 在離開路由前調用此組件,可以做一些離開此組件前的最后確認工作
                // 比如提醒用戶一些需要的信息讓其是否確認離開當前組件

                next();
            }
        }

完整的導航解析流程

  1. 導航被觸發。
  2. 在失活的組件里調用離開守衛。
  3. 調用全局的 beforeEach 守衛。
  4. 在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)。
  5. 在路由配置里調用 beforeEnter。
  6. 解析異步路由組件。
  7. 在被激活的組件里調用 beforeRouteEnter。
  8. 調用全局的 beforeResolve 守衛 (2.5+)。
  9. 導航被確認。
  10. 調用全局的 afterEach 鉤子。
  11. 觸發 DOM 更新。
  12. 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。

路由元信息

可以定義meta字段在導航守衛中通過對應的邏輯判斷此meta字段做出不同的邏輯,直接貼官方教程了,3分鐘就會

過渡動效

<router-view> 是基本的動態組件,所以我們可以用 <transition> 組件給它添加一些過渡效果,支持transition的所有屬性

<transition>
  <router-view></router-view>
</transition>
  • 單個路由組件的過渡

上面的用法會給所有路由設置一樣的過渡效果,如果你想讓每個路由組件有各自的過渡效果,可以在各路由組件內使用 <transition> 并設置不同的 name。

const Foo = {
  template: `
    <transition name="slide">
      <div class="foo">...</div>
    </transition>
  `
}

const Bar = {
  template: `
    <transition name="fade">
      <div class="bar">...</div>
    </transition>
  `
}

官網文檔3分鐘保證掌握

數據獲取

有時候我們進入一個路由需要向服務器獲取某些數據決定組件怎樣呈現,這時候Vue提供了兩種解決方案

  • 導航完成后獲取

當你使用這種方式時,我們會馬上導航和渲染組件,然后在組件的 created 鉤子中獲取數據。這讓我們有機會在數據獲取期間展示一個 loading 狀態,還可以在不同視圖間展示不同的 loading 狀態。

<template>
  <div class="post">
    <div class="loading" v-if="loading">
      Loading...
    </div>

    <div v-if="error" class="error">
      {{ error }}
    </div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>
export default {
  data () {
    return {
      loading: false,
      post: null,
      error: null
    }
  },
  created () {
    // 組件創建完后獲取數據,
    // 此時 data 已經被 observed 了
    this.fetchData()
  },
  watch: {
    // 如果路由有變化,會再次執行該方法
    '$route': 'fetchData'
  },
  methods: {
    fetchData () {
      this.error = this.post = null
      this.loading = true
      // replace getPost with your data fetching util / API wrapper
      getPost(this.$route.params.id, (err, post) => {
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}
  • 導航完成前獲取

通過這種方式,我們在導航轉入新的路由前獲取數據。我們可以在接下來的組件的 beforeRouteEnter 守衛中獲取數據,當數據獲取成功后只調用 next 方法。

export default {
  data () {
    return {
      post: null,
      error: null
    }
  },
  beforeRouteEnter (to, from, next) {
    getPost(to.params.id, (err, post) => {
      next(vm => vm.setData(err, post))
    })
  },
  // 路由改變前,組件就已經渲染完了
  // 邏輯稍稍不同
  beforeRouteUpdate (to, from, next) {
    this.post = null
    getPost(to.params.id, (err, post) => {
      this.setData(err, post)
      next()
    })
  },
  methods: {
    setData (err, post) {
      if (err) {
        this.error = err.toString()
      } else {
        this.post = post
      }
    }
  }
}

在為后面的視圖獲取數據時,用戶會停留在當前的界面,因此建議在數據獲取期間,顯示一些進度條或者別的指示。如果數據獲取失敗,同樣有必要展示一些全局的錯誤提醒。

滾動行為

使用前端路由,當切換到新路由時,想要頁面滾到頂部,或者是保持原先的滾動位置,就像重新加載頁面那樣。 vue-router 能做到,而且更好,它讓你可以自定義路由切換時頁面如何滾動。

** 注意: 這個功能只在支持 history.pushState 的瀏覽器中可用。**

            // 路由創建時可以提供一個此方法
            scrollBehavior(to, from, savedPosition) {
                // 返回期望滾動到的位置
                /* 
                    這時候我們切換user組件時就會滾動到1500y的位置
                 */
                // return {x:0,y:1500}
                // if (savedPosition) {
                //     /* 
                //         當此函數有return 一個值的話,那么savedPosition就會保存
                //         return過的值,具體大家可以直接打印看
                //      */
                //     console.log(savedPosition);
                //     return savedPosition;
                // } else {
                //     if(to.hash){
                //         return {
                //             // 可以跳轉到對應的錨點
                //             // url最后面#開頭的都是錨
                //             selector:to.hash,
                //              // vue2.6+新增了一個可選的offset選項
                //             offset:{x:number,y:number}
                //         }
                //     }else return {x:0,y:0}
                // }


                // 同時2.8vue-router新增了一個異步滾動的特性
                // 我們可以直接返回一個promise
                return new Promise((resolve, reject) => {
                    // 會等待一秒鐘滾動到y2000的位置
                    setTimeout(() => {
                        resolve({ x: 0, y: 2000 });
                    }, 1000)
                })
            }

路由懶加載

首先就是會有進階的幾個特性直接用的是鏈接,第一是覺得非常簡單,第二覺得非常難...其實最主要的是因為自己腦袋容量不是很大吧,不過這里還是一樣做一個總結吧(我給鏈接的網址真的3分鐘掌握,內容不是很多)

  • 創建一個路由
  1. 引入vue-router
  2. 創建routes對象(路由匹配規則)
  3. 通過routes創建vue-router實例
  4. 將實例掛載到vue實例上
  5. 路由完成
  • 路由傳參

    • params傳參就是路由匹配規則,寫path /:id : + 屬性名
    • path可以使用正則表達式
    • 匹配path是自上而下一次匹配,所以我們可以有一個通配符path匹配規則放在最后面就可以實現捕獲所有不存在路由(404)
    • query傳參 這個貌似沒有說好像,就是url后面的?key = value這種方式
  • 嵌套路由

    1. 每一個匹配規則都有一個children屬性,是一個數組,children里面就是一個匹配規則,里面還可以有children屬性
    2. 匹配子路由path不能寫 / 了,vue會自動補充完成路由
    3. 配置子路由還有一點必須切記,有子路由的組件一定要留坑router-view,不然到時候路由跳轉渲染不出組件,vue也不會出任何提示,這是最難的
  • 編程式導航

  1. 路由導航可以通過JavaScript實現
  2. push replace go都是可以實現路由的跳轉
  3. go是前進后退(如果步數不夠就會默默失敗)
  4. 可以傳入一個對象跳轉路由,對象規則 params傳參要么直接 -/user/:id - {path:/user/${value}}加上對應的變量,要么使用命名視圖 - {name:"/user",params:{ name:"suiyue" }},這樣params.name = suiyue了
  • 命名路由
  1. name大多數配合params傳參使用
  2. 如果匹配規則沒有name屬性的話,那么{name:"/user",params:{ name:"suiyue" }}跳轉無效只能path后面直接拼接了
  • 命名視圖
  1. 一個路由匹配一個頁面,但是真正的一個頁面怎么可能就只有一個組件呢,都是拆分出來的多個組件,所以這時候需要用到命名視圖了
  2. 可以讓一個路由顯示多個組件
  3. router-view加上name屬性制定具體的名字,沒有指定名字默認為default
  4. 路由匹配規則使用components,一個對象,key為router-view的name,value就是對應顯示的組件
  5. 命名視圖可以嵌套,就是在children中寫就行了,一定一定一定記得要留router-view的坑,不然到時候顯示不了組件又沒有任何錯誤,你懂的
  • 重定向和別名
  1. 重定向 redirect可以直接重定向到其他的路由
  2. 別名,訪問別名路由內里其實渲染的就是對應path的組件(訪問別名和path都是一樣的)
  • 路由組件傳參
  1. $route與之對應的路由高度耦合(路由出現錯誤就會導致組件內無法獲得參數)
  2. 可以在匹配規則中制定props屬性
  3. props有三種類型,
  • bool ---> 為真會將params對應的鍵值對設置到組件根元素的屬性上

  • obj ---> 為對象那么此對象對應的鍵值對就會相應設置到對應組件屬性上

  • func --> 函數可以接收一個route為參數,返回一個對象,也是設置到組件屬性上

  • html5History模式

  1. 只需要在實例化Vue時添加上mode:"history"就可以使用history模式了,但是需要配置好服務器
  • 導航守衛

    1. 全局前置守衛 --> beforeEach
    2. 全局解析守衛 --> beforeResolve --> 2.5+
    3. 全局后置鉤子 --> afterEach
    4. 路由獨享守衛 -->beforeEnter
    5. 組件內的守衛
    • beforeRouteEnter (next有回調,接收對應組件實例)
    • beforeRouteUpdate 2.2+
    • beforeRouteLeave
  • 完整的導航解析流程

    1. 導航被觸發。
    2. 在失活的組件里調用離開守衛。
    3. 調用全局的 beforeEach 守衛。
    4. 在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)。
    5. 在路由配置里調用 beforeEnter。
    6. 解析異步路由組件。
    7. 在被激活的組件里調用 beforeRouteEnter。
    8. 調用全局的 beforeResolve 守衛 (2.5+)。
    9. 導航被確認。
    10. 調用全局的 afterEach 鉤子。
    11. 觸發 DOM 更新。
    12. 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。
  • 路由元信息

    • 定義路由匹配規則時可以加上meta字段是一個對象,元信息,就是用來確定路由的一些信息,通過這些信息我們可以更好的在鉤子函數中判斷元信息的參數判斷是否決定繼續路由或者跳轉到其他路由(記住next跳轉其他路由的坑)
  • 過渡動效

    1. 我們可以直接給router-view包裹一個transition組件,其實最終router-view就是一個殼,包裹的還是router-view對應的組件,相當于每一個組件的切換就像transition包裹component一樣,通過is改變渲染的組件

    2. 但是上面的方法決定了所有的組件的動效都會一樣的(一個transition),可能我們需要在組件切換時加上不同的過渡效果,就需要在每一個組件的內部包裹一個對應的transition(有一點一直沒搞懂,就是不知道樣式怎么分開寫,應該是必須指定一個name吧,不然全都是一樣的樣式了)

  • 數據獲取

    1. 導航完成后獲取
    • 這種方式會馬上導航和渲染組件,然后在新渲染的組件的created鉤子中獲取數據
    • 那么在獲取數據的過程中,對應的組件就必須有一個loding圖了
    1. 導航完成前獲取
    • 這種方式我們會在導航轉入新的路由前獲取數據
    • 在接下來組件的鉤子beforeRouterEnter守衛中獲取數據
    • 數據獲取成功調用next()方法
    • 這樣的話就必須在當前的組件中渲染一個進度條或者別的提示了
  • 滾動行為

    1. 可以在實例化vue-router時接收一個scrollBehavior函數,通過這個函數我們可以控制路由跳轉時的默認滾動行為
    2. 此函數可以返回一個具體坐標值 {x:0,y:0}這種
    3. 每一次scrollBehavior函數成功返回一個具體坐標后savedPosition參數就會記錄對應的坐標,下次就可以直接返回了
    4. 同樣可以返回錨點跳轉,通過在url傳入對應的hash完成
    5. 2.6+ 中還有一個可選的offset參數可以使用

有一點要給大家說清楚,這里所有的版本要求都是要求的vue-router插件版本,大家會不會以為是vue的版本呢?大家如果學習前端的時候有什么疑惑或者想跟我交流的可以加下QQ群:78484----> 5854 (感謝)

latest update: 2019-06-30 09:15:04

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • 學習目的 學習Vue的必備技能,必須 熟練使用 Vue-router,能夠在實際項目中運用。 Vue-rout...
    _1633_閱讀 92,406評論 3 58
  • vue-router學習筆記 安裝 并且如果在一個模塊化工程中使用它,必須要通過Vue.use()明確地安裝路由功...
    EL_PSY_CONGROO閱讀 593評論 0 0
  • 一、Vue-router之集成 1. 功能 處理前端路由的功能 2. 安裝 npm install vue-rou...
    六寸光陰丶閱讀 2,538評論 0 0
  • 安裝vue-router npm install vue-router --save-dev 路由配置文件src/...
    defer閱讀 630評論 0 1
  • 1.如何在Vue-cli腳手架中增加子頁面? 在src目錄下面新建文件頁面(以Vue結尾)文件內容 然后在rout...
    鄭宋君閱讀 634評論 0 0