Vue(基础八)_导航守卫(组件内的守卫)
一、前言
主要通过一个例子演示三个钩子的作用:
1、beforeRouteEnter()
2、beforeRouteUpdate()
3、beforeRouteLeave
二、主要内容
1、举例说明:下面有三个组件,用户1,用户2公用一个公共组件。
2、beforeRouteEnter()
(1)详细说明beforeRouteEnter
//在路由改变之前 beforeRouteEnter (to, from, next){ //在渲染该组件的对应路由被confirm前调用 //不能获取当前组件实例this,因为在守卫执行之前,实例还没有被创建 //但是你可以通过传一个回调函数给next来访问组件实例。在导航被确认的时候进行回调,并且把组件实例作为回调方法的参数 } /* */
(2)实现beforeRouteEnter的代码以及演示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="app"></div> <script src="vue.js"></script> <script type="text/javascript" src="vue-router.js"></script> <script type="text/javascript" src="axios.js"></script> <script type="text/javascript"> Vue.use(VueRouter) //用户组件 var User = { data(){ return{ user:'', error:null, timer:null, num:0, msg:'',//输入框中输入的内容 msg1:'',//页面中展示的数据 confirm:true } }, template:`<div> <div>{{num}}</div> <input type="text" v-model='msg'/> <p>{{msg1}}</p> <button>保存</button> <div v-if="error" class = 'error'>{{error}}</div> <div class='user' v-if='user'> {{user}} </div> </div>`, methods:{ setDatas(user){ this.user = user; }, setError(err){ this.error=err; } }, beforeRouteEnter(to,from,next){ //在渲染该组件的对应路由被confirm前调用 //不能获取组件实例this //因为当守卫执行前,组件还没创建,也就是路由切换之前 //但是你可以通过传一个回调给next来访问组件实例。在导航被确认的时候执行回调,并将组件实例作为回调方法的参数 //全局的axios调用 console.log(to); axios.get(`http://127.0.0.1:8888/user/${to.params.id}`) .then(res=>{ next(vm=>vm.setDatas(res.data)); }) .catch(err=>{ next(vm => vm.setError(err)) }) } } //测试组件 var Test = { template:`<div>我是测试组件</div>` } //路由配置 var router = new VueRouter({ routes:[{ path:'/user/:id', name:'user', component:User },{ path:'/test', name:'test', component:Test }] }) //入口组件 var App = { template:`<div> <router-link :to='{name: "test"}'>测试</router-link> <router-link :to='{name:"user",params:{id:1}}'>用户1</router-link> <router-link :to='{name:"user",params:{id:2}}'>用户2</router-link> <router-view></router-view> </div>` } //创建vue实例 new Vue({ el:'#app', data:{ }, components:{ App }, template:'<App/>', router }) </script> </body> </html>
(3)具体实现
(4)测试:当从“测试”组件进入到用户组件的时候,发现组件中的内容发生改变,但是当从用户1切换到用户2的时候,发现没反应,因为用户1和用户2公用的公共组件user,
“用户1”切换到“用户2”的时候没有组件的创建和销毁
2、beforeRouteUpdate()
(1)在组件内部可以用beforeRouteUpdate来解决上面出现的问题
//路由更新时 beforeRouteUpdate(to, from, next) { //在当前路由改变,但是该组件被复用时调用 //举例来说:对于一个带有动态参数的路径 /foo/:id, 在/foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的foo组件, 因此组件实例会被重复利用。 此时这个钩子就可以在这个时候调用 //在这里可以获取到当前的this }
(2)beforeRouteUpdate的代码如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="app"></div> <script src="vue.js"></script> <script type="text/javascript" src="vue-router.js"></script> <script type="text/javascript" src="axios.js"></script> <script type="text/javascript"> Vue.use(VueRouter) //用户组件 var User = { data(){ return{ user:'', error:null, timer:null, num:0, msg:'',//输入框中输入的内容 msg1:'',//页面中展示的数据 confirm:true } }, template:`<div> <div>{{num}}</div> <input type="text" v-model='msg'/> <p>{{msg1}}</p> <button>保存</button> <div v-if="error" class = 'error'>{{error}}</div> <div class='user' v-if='user'> {{user}} </div> </div>`, methods:{ setDatas(user){ this.user = user; }, setError(err){ this.error=err; } }, beforeRouteEnter(to,from,next){ //在渲染该组件的对应路由被confirm前调用 //不能获取组件实例this //因为当守卫执行前,组件还没创建,也就是路由切换之前 //但是你可以通过传一个回调给next来访问组件实例。在导航被确认的时候执行回调,并将组件实例作为回调方法的参数 //全局的axios调用 console.log(to); axios.get(`http://127.0.0.1:8888/user/${to.params.id}`) .then(res=>{ next(vm=>vm.setDatas(res.data)); }) .catch(err=>{ next(vm => vm.setError(err)) }) }, beforeRouteUpdate(to, from, next){ this.$axios.get(`http://127.0.0.1:8888/user/${to.params.id}`). then(res=>{ this.setDatas(res.data); next(); //一定要用next,不然会被卡主 }) .catch(err=>{ this.setError(err); next(); }) } } //测试组件 var Test = { template:`<div>我是测试组件</div>` } //路由配置 var router = new VueRouter({ routes:[{ path:'/user/:id', name:'user', component:User },{ path:'/test', name:'test', component:Test }] }) Vue.prototype.$axios = axios //入口组件 var App = { template:`<div> <router-link :to='{name: "test"}'>测试</router-link> <router-link :to='{name:"user",params:{id:1}}'>用户1</router-link> <router-link :to='{name:"user",params:{id:2}}'>用户2</router-link> <router-view></router-view> </div>` } //创建vue实例 new Vue({ el:'#app', data:{ }, components:{ App }, template:'<App/>', router }) </script> </body> </html>
(3)测试:发现公共组件部分,可以通过切换路由,渲染出各自的数据了
3、beforeRouteLeave
(1)beforeRouteLeave()
beforeRouteLeave(to, from, next){ //离开当前组件时调用 }
(2)可以利用这个方法当用户离开某个页面的时候,提示用户保存信息
比如在写博客是点击其他页面时,会提示是否保存当前内容
(3)具体代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="app"></div> <script src="vue.js"></script> <script type="text/javascript" src="vue-router.js"></script> <script type="text/javascript" src="axios.js"></script> <script type="text/javascript"> Vue.use(VueRouter) //用户组件 var User = { data(){ return{ user:'', error:null, timer:null, num:0, msg:'',//输入框中输入的内容 msg1:'',//页面中展示的数据 confirm:true } }, template:`<div> <div>{{num}}</div> <input type="text" v-model='msg'/> <p>{{msg1}}</p> <button @click="save">保存</button> <div v-if="error" class = 'error'>{{error}}</div> <div class='user' v-if='user'> {{user}} </div> </div>`, methods:{ setDatas(user){ this.user = user; }, setError(err){ this.error=err; }, save(){ this.msg1 = this.msg; this.msg = ''; this.confirm = true; } }, beforeRouteEnter(to,from,next){ //在渲染该组件的对应路由被confirm前调用 //不能获取组件实例this //因为当守卫执行前,组件还没创建,也就是路由切换之前 //但是你可以通过传一个回调给next来访问组件实例。在导航被确认的时候执行回调,并将组件实例作为回调方法的参数 //全局的axios调用 console.log(to); axios.get(`http://127.0.0.1:8888/user/${to.params.id}`) .then(res=>{ next(vm=>vm.setDatas(res.data)); }) .catch(err=>{ next(vm => vm.setError(err)) }) }, beforeRouteUpdate(to, from, next){ //当前路由改变,但是组件被复用(也就是公共组件) this.$axios.get(`http://127.0.0.1:8888/user/${to.params.id}`). then(res=>{ this.setDatas(res.data); next(); //一定要用next,不然会被卡主 }) .catch(err=>{ this.setError(err); next(); }) }, beforeRouteLeave(to, from, next){ //导航离开该组件的对应路由时调用 if (this.confirm == true && this.msg) { //证明用户输入了内容 需要提示用户 保存重要信息 this.confirm= confirm('请保存重要信息'); //用户点击了取消按钮 返回值为false next(false); }else if(this.confirm == false){ alert('请保存信息后退出'); next(false); }else{ next();//放行路由 } } } //测试组件 var Test = { template:`<div>我是测试组件</div>` } //路由配置 var router = new VueRouter({ routes:[{ path:'/user/:id', name:'user', component:User },{ path:'/test', name:'test', component:Test }] }) Vue.prototype.$axios = axios //入口组件 var App = { template:`<div> <router-link :to='{name: "test"}'>测试</router-link> <router-link :to='{name:"user",params:{id:1}}'>用户1</router-link> <router-link :to='{name:"user",params:{id:2}}'>用户2</router-link> <router-view></router-view> </div>` } //创建vue实例 new Vue({ el:'#app', data:{ }, components:{ App }, template:'<App/>', router }) </script> </body> </html>
三、总结
beforeRouteEnter:用于组件创建之前,公共组件不起作用
beforeRouteUpdate:用于公共组件的情况
参考文章:https://juejin.im/post/5b41bdef6fb9a04fe63765f1#heading-17