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>
beforeRouteEnter

(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>
beforeRouteUpdate

(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>
beforeRouteLeave

 

 

 

 

三、总结                                                                                            

beforeRouteEnter:用于组件创建之前,公共组件不起作用

beforeRouteUpdate:用于公共组件的情况

 参考文章:https://juejin.im/post/5b41bdef6fb9a04fe63765f1#heading-17

posted @ 2019-04-08 19:42  mysunshine_SZZ  阅读(2820)  评论(0编辑  收藏  举报