導航守衛解釋與例子

「導航」表示路由正在發生改變。javascript

正如其名,vue-router 提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程當中:全局的, 單個路由獨享的, 或者組件級的。html

記住參數或查詢的改變並不會觸發進入/離開的導航守衛。你能夠經過觀察 $route 對象來應對這些變化,或使用 beforeRouteUpdate 的組件內守衛。vue

一、全局前置守衛

你可使用 router.beforeEach 註冊一個全局前置守衛:java

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

當一個導航觸發時,全局前置守衛按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛 resolve 完以前一直處於 等待中vue-router

每一個守衛方法接收三個參數:api

  • to: Route: 即將要進入的目標 路由對象瀏覽器

  • from: Route: 當前導航正要離開的路由app

  • next: Function: 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。異步

    • next(): 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。ide

    • next(false): 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。

    • next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向 next 傳遞任意位置對象,且容許設置諸如 replace: truename: 'home' 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。

    • next(error): (2.4.0+) 若是傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回調。

確保要調用 next 方法,不然鉤子就不會被 resolved。 完整例子以下:

<body class="">
    <script src="../js/vue.js"></script>
    <script src="../js/vue-router.js"></script>
    <div id="app">
        <h1>導航守衛</h1>
       <router-link :to="{ name: 'user', params: { id: 123 }}">User</router-link>
        <br />
        <router-link to="/user/222">b title</router-link>
        <router-view></router-view>
    </div>
    <script>
    var user = {
        template: "<div>this is user </div>"
    };

    const router = new VueRouter({
        routes: [{
            path: "/user/:id",
			name:"user",
            component: user,
        }],
		
    })
	router.beforeEach((to,from,next)=>{
	 console.log(to);
	 //console.log(to.name);//user
	 next();
	})
    const app = new Vue({ router }).$mount("#app")
	//:to="{ name: 'user', params: { id: 123 }}" 前面的:不能省略,須要得到路由path裏面的id
    </script>
</body>

二、全局解析守衛

在 2.5.0+ 你能夠用 router.beforeResolve 註冊一個全局守衛。這和 router.beforeEach 相似,區別是在導航被確認以前,同時在全部組件內守衛和異步路由組件被解析以後,解析守衛就被調用。

路由攔截是咱們項目中常常遇到的廣泛問題,例如當你訪問任何一個頁面的時候須要驗證該用戶有沒有登陸等;
對此,vue-router提供的beforeRouter能夠方便的實現路由的導航守衛;

router.beforeResolve((to, from, next) => {
  /* must call `next` */
})

三、全局後置鉤子

你也能夠註冊全局後置鉤子,然而和守衛不一樣的是,這些鉤子不會接受 next 函數也不會改變導航自己:

router.afterEach((to, from) => {
  // ...
})

四、路由獨享的守衛

你能夠在路由配置上直接定義 beforeEnter 守衛:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

這些守衛與全局前置守衛的方法參數是同樣的。

五、組件內的守衛

最後,你能夠在路由組件內直接定義如下路由導航守衛:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對應路由被 confirm 前調用
    // 不!能!獲取組件實例 `this`
    // 由於當守衛執行前,組件實例還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,可是該組件被複用時調用
    // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。
    // 能夠訪問組件實例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該組件的對應路由時調用
    // 能夠訪問組件實例 `this`
  }
}

beforeRouteEnter 守衛 不能 訪問 this,由於守衛在導航確認前被調用,所以即將登場的新組件還沒被建立。

不過,你能夠經過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,而且把組件實例做爲回調方法的參數。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 經過 `vm` 訪問組件實例
  })
}

完整例子:

<body class="">
    <script src="../js/vue.js"></script>
    <script src="../js/vue-router.js"></script>
    <div id="app">
        <h1>導航守衛</h1>
        <router-link :to="{ name: 'user', params: { id: 123 }}">User</router-link>
        <br />
        <router-link to="/user/222">b title</router-link>
        <router-view></router-view>
    </div>
    <script>
    var user = {
        data() {
            return {
                num: 18
            }
        },
        template: "<div>this is user {{num}} </div>",
        beforeRouteEnter(to, from, next) {
            next(vm => {
                vm.num = 19;//從新爲num賦值19
                console.log(vm)
            })
        }
    };
   
    const router = new VueRouter({
        routes: [{
            path: "/user/:id",
            name: "user",
            component: user,
        }],

    })

    const app = new Vue({ router }).$mount("#app")
    //點擊連接展現this is user 19
    //:to="{ name: 'user', params: { id: 123 }}" 前面的:不能省略,須要得到路由path裏面的id
    </script>
</body>

注意 beforeRouteEnter 是支持給 next 傳遞迴調的惟一守衛。對於 beforeRouteUpdate 和 beforeRouteLeave 來講,this 已經可用了,因此不支持傳遞迴調,由於沒有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

完整例子:

<body class="">
    <script src="../js/vue.js"></script>
    <script src="../js/vue-router.js"></script>
    <div id="app">
        <h1>導航守衛</h1>
        <router-link to="/user/111">User</router-link>
        <br />
        <router-link to="/user/222">b title</router-link>
        <router-view></router-view>
    </div>
    <script>
    var user = {
        data() {
            return {
                name: "lily"
            }
        },
        template: "<div>this is user {{name}} </div>",
        beforeRouteUpdate(to, from, next) {
		    this.name = "jack"
			console.log(to)
            next()
        }
    };
   
    const router = new VueRouter({
        routes: [{
            path: "/user/:id",
            name: "user",
            component: user,
        }],

    })

    const app = new Vue({ router }).$mount("#app")
    </script>
</body>

這個離開守衛一般用來禁止用戶在還未保存修改前忽然離開。該導航能夠經過 next(false) 來取消。

beforeRouteLeave (to, from , next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

完整例子:

<body class="">
    <script src="../js/vue.js"></script>
    <script src="../js/vue-router.js"></script>
    <div id="app">
        <h1>導航守衛</h1>
        <router-link to="/user">User</router-link>
        <br />
        <router-link to="/seller">seller</router-link>
        <router-view></router-view>
    </div>
    <script>
    var user = {
        data() {
            return {
                name: "lily"
            }
        },
        template: "<div>this is user {{name}} </div>",
        beforeRouteLeave(to, from, next) {
            const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
            if (answer) {
                next()
            } else {
                next(false)
            }
        }
    };
    var seller = {

        template: "<div>this is seller </div>",

    };
    const router = new VueRouter({
        routes: [{
            path: "/user",
            name: "user",
            component: user,
        }, {
            path: "/seller",
            name: "seller",
            component: seller,
        }],

    })

    const app = new Vue({ router }).$mount("#app")
	//點擊另一個鏈接準備離開此鏈接觸發beforeRouteLeave
    </script>
</body>

完整的導航解析流程

  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 的回調函數。
相關文章
相關標籤/搜索