八、vue基础-router基础、动态参数、组件复用、配置404、嵌套路由、编程式导航、命名视图、重定向、导航守卫

1.基本使用
  a.创建一个VueRouter对象:new VueRouter()
  b.在VueRouter中,需要传递一个routes参数,这个参数是一个数组类型,数据中存储的是对象,对象中最少有两个属性,一个是path代表的是url,一个是component代表数据更新的组件,代码如下:

let router = new VueRouter({
                routes:[
                {path:"/",component:index},
                {path:"/find",component:find},
                {path:"/friend",component:friend}
                ]

  .将router传给Vue
  d.把网页中之前的a标签替换成router-link标签
  e.使用router-view指定网页中那个地方要被更新。 全部代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src="vue-router.js"></script>
            <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
            <title>vue-router练习</title>
        </head>
        <body>
            <div id='app'>
                <nav class="navbar navbar-default">
                    <div class="container-fluid">
                    <!-- Brand and toggle get grouped for better mobile display -->
                    <div class="navbar-header">
                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        </button>
                        <router-link to="/" class="navbar-brand">我的音乐</router-link>
                    </div>
                    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                        <ul class="nav navbar-nav">
                        <li class="active">
                            <router-link to="/">首页</router-link>
                        </li>
                        <li>
                            <router-link to="/find">发现音乐</router-link>
                        </li>
                        <li>
                            <router-link to="/friend">我的朋友</router-link>
                        </li>
                        </ul>
                    </div><!-- /.navbar-collapse -->
                    </div><!-- /.container-fluid -->
                </nav> 
                <div class="container">
                    <router-view></router-view>
                </div>
            </div>
            <script>
            var index = Vue.extend({template:"<h1>首页</h1>"})
            var find = Vue.extend({template:"<h1>发现音乐</h1>"})
            var friend = Vue.extend({template:"<h1>我的朋友</h1>"})
            let router = new VueRouter({
                routes:[
                {path:"/",component:index},
                {path:"/find",component:find},
                {path:"/friend",component:friend}
                ]
            })
                new Vue({
                    el:'#app',
                    // router:router
                    router
                })
            </script>
        </body>
        </html>

2.动态路由
  1.在url中,通过定义一个参数那么以后url中就可以动态的传递这个参数,语法是:/profile/:参数名
  2.在组件中可以通过this.$route.params.参数名拿到,或者是组件中的模块中,可以通过$route.params.参数名拿到
  3.this.$route和this.$router的区别:
    a.this.$route:代表是当前这个路由的信息集合
    b.this.$router:代表是全局的VueRouter对象
代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src="vue-router.js"></script>
            <title>动态参数</title>
        </head>
        <body>
            <div id='app'>
                <ul>
                    <li>
                        <router-link to="/">首页</router-link>
                    </li>
                    <li>
                        <router-link to="profile/123">个人中心</router-link>
                    </li>
                </ul>
                <router-view></router-view>
            </div>
            <script>
                let index = Vue.extend({template:"<h1>首页来了</h1>"})
                let profile = Vue.extend({template:"<h1>个人中心来了:{{$route.params.userid}}</h1>"})

                let router =  new VueRouter({
                    routes:[
                        {path:"/",component:index},
                        {path:"/profile/:userid",component:profile},
                    ]
                })
                new Vue({
                    el:'#app',
                    router
                })
            </script>
        </body>
        </html>

3.组件复用:当使用路由参数时,原来组件的实力会被复用,意味着组件的生命周期钩子不会再被调用。有两种方法解决:
  a.监听this.$router属性,通过判断to和from来更新数据
  b.使用导航守卫的beforeRouteUpdate方法们也可以获取to和from,但是要记得调用next(),否则页面不会更新

<!DOCTYPE html>
    <html lang='en'>
    <head>
        <meta charset='UTF-8'>
        <meta name='viewport' content='width=device-width, initial-scale=1.0'>
        <meta http-equiv='X-UA-Compatible' content='ie=edge'>
        <script src='vue.js'></script>
        <script src="vue-router.js"></script>
        <title>组件复用</title>
    </head>
    <body>
        <div id='app'>
            <ul>
                <li>
                    <router-link to="/profile/张三">张三的个人中心</router-link>
                </li>
                <li>
                    <router-link to="/profile/李四">李四的个人中心</router-link>
                </li>
            </ul>
            <router-view></router-view>
        </div>
        <script>
            let index = Vue.extend({
                template:"<h1>首页来了</h1>"
            })
            let profile = Vue.extend({
                template:"<h1>个人中心来了:{{$route.params.userid}}</h1>",
                mounted(){
                    console.log(this.$route.params.userid);
                },
                // watch:{
                //     "$route": function(to,from){
                //         console.log("to:",to);
                //         console.log("from:",from);
                //         console.log('看看执行么有');
                //     }
                beforeRouteUpdate: function(to,from,next){
                    console.log("to:",to);
                    console.log("from:",from);
                    next()  
                }
            })

            let router =  new VueRouter({
                routes:[
                    {path:"/",component:index},
                    {path:"/profile/:userid",component:profile},
                ]
            })
            new Vue({
                el:'#app',
                router
            })
        </script>
    </body>
    </html>  

4.404配置:
  a.前端页面配置:子啊所有路由后面增加一个*的url,让这个url映射到一个404的组件
  b.数据不存在的处理:通过访问服务器来判断,可以通过 this.$router.replace("/404"),跳转到404页面
代码如下:

<!DOCTYPE html>
    <html lang='en'>
    <head>
        <meta charset='UTF-8'>
        <meta name='viewport' content='width=device-width, initial-scale=1.0'>
        <meta http-equiv='X-UA-Compatible' content='ie=edge'>
        <script src='vue.js'></script>
        <script src="vue-router.js"></script>
        <title>404配置</title>
    </head>
    <body>
        <div id='app'>
            <router-view></router-view>
        </div>
        <script>
            let index = Vue.extend({
                template:"<h1>首页</h1>"
            })
            let aboutus = Vue.extend({
                template:"<p>关于我们</p>"
            })
            let profile = Vue.extend({
                template:"<p>个人中心:{{$route.params.userid}}</p>",
                mounted(){
                    if(this.$route.params.userid !='123'){
                        this.$router.replace("/404")
                    }
                },
            })
            let notfound = Vue.extend({
                template:"<p>404页面没有找到</p>"
            })
            let router = new VueRouter({
                routes:[
                    {path:"/",component:index},
                    {path:"/aboutus",component:aboutus},
                    {path:"/profile/:userid",component:profile},
                    {path:"/404",component:notfound},
                    {path:"*",component:notfound},
                ]
            })
            new Vue({
                el:'#app',
                router:router
            })
        </script>
    </body>
    </html>

5.路由嵌套(子路由)
  a.在大的路由下面,需要子路由切换数据的时候,可以使用路由嵌套
  b.定义路由的时候,不需要在routes中单独添加映射,而应该放在父路由的childern中
  c.在父路由的组件中,要谈价路由出口
代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src='vue-router.js'></script>
            <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
            <title>嵌套路由</title>
        </head>
        <body>
            <div id='app'>
                <nav class="navbar navbar-default">
                    <div class="container">
                        <div class="navbar-header">
                            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                                <span class="sr-only">哈哈</span>
                                <span class="icon-bar"></span>
                                <span class="icon-bar"></span>
                                <span class="icon-bar"></span>
                            </button>
                            <a class="navbar-brand" href="#">学习</a>
                        </div>
                        <div class="collapse navbar-collapse" id="bs-example-navber-collapse-1">
                            <ul class="nav navbar-nav">
                                <li class ="active">
                                    <router-link to="/">首页</router-link>
                                </li>
                                <li>
                                    <router-link to="/user/123">我的主页</router-link>
                                </li>
                            </ul>
                        </div>
                    </div>
                </nav>
                <div class="container">
                    <router-view></router-view>
                </div>
            </div>
            <script>
                let index=Vue.extend({
                    template:"<h1>首页</h1>"
                })
                let user=Vue.extend({
                    template:`
                    <div>
                        <h1>我的主页</h1>
                        <ul class="nav nav-tabs">
                            <li role="presentation" class="active">
                                <router-link to="/user/123/users">设置</router-link>
                            </li>
                            <li role="presentation">
                                <router-link to="/user/123/xiaoxi">消息</router-link>
                            </li>
                        </ul>
                        <div class="container">
                            <router-view></router-view>
                        </div>
                    </div> 
                    `
                })
                let users=Vue.extend({
                    template:"<h3>个人中心</h3>"
                })
                let xiaoxi=Vue.extend({
                    template:"<h3>个人消息</h3>"
                })
                let router=new VueRouter({
                    routes:[
                        {path:"/",component:index},
                        {
                            path:"/user/:userid",
                            component:user,
                            children:[
                                {path:"",component:users},
                                {path:"users",component:users},
                                {path:"xiaoxi",component:xiaoxi},
                            ]
                        },
                    ]
                })
                new Vue({
                    el:'#app',
                    router
                })
            </script>
        </body>
        </html>

6.编程试导航
  a. this.$router.puth:转到下一个url,会把新转入的url添加到浏览器的history中,push的参数:
  字符串:直接就是路径
  对象:path和name都可以,但是如果是使用了path,参数要放在path,放在params中没有效果
  b. this.$router.replace:用法和push是一样的,区别是替换当前页面
  c. this.$router.go:往前、往后
代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src='vue-router.js'></script>
            <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
            <title>嵌套路由</title>
        </head>
        <body>
            <div id='app'>
                <button @click="gotoPost">跳到帖子列表</button>
                <button @click="gotoProfile">跳到个人中心</button>
                <button @click="gotoLogin">登录</button>
                <button @click="gotoNext">下一步</button>
                <button @click="gotoUp">上一步</button>
                <router-view></router-view>
            </div>
            <script>
                let post=Vue.extend({
                    template:"<h1>帖子列表</h1>"
                })
                let profile=Vue.extend({
                    template:"<h3>个人中心:{{$route.params.userid}}</h3>"
                })
                let login=Vue.extend({
                    template:"<h3>登录界面,打印$route.query{{$route.query}},打印$route.params{{$route.params}},打印$route.fullPath{{$route.fullPath}}</h3>"
                })
                let router=new VueRouter({
                    routes:[
                        {path:"/post",component:post},
                        {path:"/profile/:userid",component:profile,name:"myprofile"},
                        {path:"/login",component:login},
                    ]
                })
                new Vue({
                    el:'#app',
                    router:router,
                    methods:{
                        gotoPost(){
                        this.$router.push("/post")
                        },
                        gotoProfile(){
                            // this.$router.push("/profile/123")
                            // this.$router.push({path:"/profile/123"})
                            // this.$router.push({name:"myprofile",params:{userid:"222"}})
                            this.$router.replace({name:"myprofile",params:{userid:"222"}})
                        },
                        gotoLogin(){
                            let currentPath = this.$route.fullPath
                            this.$router.push({path:"/login",query:{from:currentPath}})
                        },
                        gotoNext(){
                            this.$router.go(1)
                        },
                        gotoUp(){
                            this.$router.go(-1)
                        }           
                    }
                })
            </script>
        </body>
        </html>

7.命名视图
  a.路由名称:可以在定义路由的时候指定name,使用的时候们可以直接传递name值就可以了
  b.命名视图(多组件):在一个页面中,可以通过命名视图展示多个组件,有一下步骤:
    (1)在定义路由的时候们需要传递components,然后把所有需要展示的路由都放到这个里面,components是一个对象,{name:组件}的映射。
    (2)在模板中,就是通过 <router-view name="组件名"></router-view>来实现
代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src='vue-router.js'></script>
            <title>命名视图</title>
            
            <style>
                .header{
                    width: 100%;
                    height: 80px;
                    background: cadetblue;
                }
                .body{
                    display: flex;
                    height: 500px;
                }
                .body .sidebar{
                    width: 200px;
                    background: darkgrey;
                }
                .body .main{
                    flex: 1;
                    background: cyan;
                }   
                .footer{
                    height: 100px;
                    background: darksalmon;
                }
                
            </style>
        </head>
        <body>
            <div id='app'>
                <div class="header">
                    <router-view name="header"></router-view>
                </div>
                <div class="body">
                    <div class="sidebar">
                        <router-view name="sidebar"></router-view>
                    </div>
                    <div class="main">
                        <router-view name="main"></router-view>
                    </div>
                </div>
                <div class="footer">
                    <router-view name="footer"></router-view>
                </div>
            </div>
            <script>
                let header = Vue.extend({
                    template:"<div>这个是header部分</div>"
                })
                let sidebar = Vue.extend({
                    template:"<div>这个是sidebar部分</div>"
                })
                let main = Vue.extend({
                    template:"<div>这个是main部分</div>"
                })
                let footer = Vue.extend({
                    template:"<div>这个是footer部分</div>"
                })
                let router = new VueRouter({
                    routes:[
                        {path:"/",components:{
                            header:header,
                            sidebar:sidebar,
                            main:main,
                            footer:footer
                        }}
                    ]
                })
                new Vue({
                    el:'#app',
                    router
                })
            </script>
        </body>
        </html>

8.重定向和别名:
  a.重定向:在定义路由的时候,可以加一个redirect参数,用来重定向到另外一个页面。
  b.别名:在定义的时候,可以加一个alias参数,用来标识这个url的别名,之后可以通过别名可以访问到这个页面。

<!DOCTYPE html>
    <html lang='en'>
    <head>
        <meta charset='UTF-8'>
        <meta name='viewport' content='width=device-width, initial-scale=1.0'>
        <meta http-equiv='X-UA-Compatible' content='ie=edge'>
        <script src='vue.js'></script>
        <script src='vue-router.js'></script>
        <title>重定向和别名</title>
    </head>
    <body>
        <div id='app'>
            <router-view></router-view>
        </div>
        <script>
            let index = {template:"<h1>首页</h1>"}
            let login = {template:"<h1>登录</h1>"}
            let router = new VueRouter({
                routes:[
                    {path:"/",redirect:'/login'},
                    {path:"/login",component:login,alias:"/test"}
                ]
            })
            new Vue({
                el:'#app',
                router
            })
        </script>
    </body>
    </html>

9.导航守卫-全局导航守卫:在VueRouter上实现的,有两个函数,beforeEach、afterEach
  1.beforeEach(to,from,next) to:代表上一个路由。from:代表下一个路由对象。next:代表是控制下一步路由怎么走
  next()按照正常的流程来
  next("/")就会把之前的路由断掉,走到首页中去
  next(false)或者没有调用next() 不会做任务跳转
  2.afterEach(to,from) 路由完成后回调
代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src='vue-router.js'></script>
            <title>全局导航守卫</title>
        </head>
        <body>
            <div id='app'>
                <router-link to="/">首页</router-link>
                <router-link to="/account">我的账户</router-link>
                <router-link to="/order">我的订单</router-link>
                <router-link to="/login">登录界面</router-link>
                <router-view></router-view>
            </div>
            <script>
                // const logined=false
                const logined=true
                let index = {template:"<h1>首页</h1>"}
                let account = {template:"<h1>我的账户</h1>"}
                let order = {template:"<h1>我的订单</h1>"}
                let login = {template:"<h1>登录界面</h1>"}
                var router = new VueRouter({
                    routes:[
                        {path:"/",component:index,name:"index"},
                        {path:"/account",component:account,name:"account"},
                        {path:"/order",component:order,name:"order"},
                        {path:"/login",component:login,name:"login"}
                    ]
                })
                router.beforeEach(function(to,from,next){
                    //next()按照正常的流程来
                    //next("/")就会把之前的路由断掉,走到首页中去
                    //next(false)或者没有调用next() 不会做任务跳转
                    //请求需要授权的路由
                    const authRouters=['account','order']
                    //判断有没有下标
                    if(authRouters.indexOf(to.name)>=0){
                        //如果没有登录
                        console.log('name',to.name);
                        if(!logined){
                            next('/login')
                        }else{
                            next()
                        }
                    //如果是访问登录页面
                    }else if(to.name=='login'){
                        //如果登录了,到首页
                        if(logined){
                            next('/')
                        }else{
                            next()
                        }
                    }else{
                        next()
                    }
                })
                router.afterEach(function(to,from){
                    console.log('to',to);
                    console.log('from',from);
                })
                new Vue({
                    el:'#app',
                    router
                })
            </script>
        </body>
        </html>


10.导航守卫--路由导航守卫:beforeEnter:function(to,from,next)
代码如下:

<!DOCTYPE html>
            <html lang='en'>
            <head>
                <meta charset='UTF-8'>
                <meta name='viewport' content='width=device-width, initial-scale=1.0'>
                <meta http-equiv='X-UA-Compatible' content='ie=edge'>
                <script src='vue.js'></script>
                <script src='vue-router.js'></script>
                <title>路由导航守卫</title>
            </head>
            <body>
                <div id='app'>
                    <router-link to="/">首页</router-link>
                    <router-link to="/account">我的账户</router-link>
                    <router-link to="/order">我的订单</router-link>
                    <router-link to="/login">登录界面</router-link>
                    <router-view></router-view>
                </div>
                <script>
                    const logined=true
                    //const logined=false
                    let index = {template:"<h1>首页</h1>"}
                    let account = {template:"<h1>我的账户</h1>"}
                    let order = {template:"<h1>我的订单</h1>"}
                    let login = {template:"<h1>登录界面</h1>"}
                    var router = new VueRouter({
                        routes:[
                            {path:"/",component:index,name:"index"},
                            {path:"/account",component:account,name:"account"},
                            {path:"/order",component:order,name:"order"},
                            {path:"/login",component:login,name:"login",beforeEnter:function(to,from,next){
                                if(logined){
                                    next("/")
                                }else{
                                    next()
                                }
                            }}
                        ]
                    })

                    new Vue({
                        el:'#app',
                        router
                    })
                </script>
            </body>
            </html>

11.导航路由--组件导航守卫:
  beforeRouteEnter:function(to,from,next):当前页面被进入之前调用
  beforeRouteUpdate:function(to,from,next):当前页面被复用,参数改变了会调用
  beforeRouteLeave(to,from,next):当前页面即将离开调用
代码如下:

<!DOCTYPE html>
        <html lang='en'>
        <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1.0'>
            <meta http-equiv='X-UA-Compatible' content='ie=edge'>
            <script src='vue.js'></script>
            <script src='vue-router.js'></script>
            <title>组件导航守卫</title>
        </head>
        <body>
            <div id='app'>
                <router-link to="/">首页</router-link>
                <router-link to="/account/111">111我的账户</router-link>
                <router-link to="/account/222">222我的账户</router-link>
                <router-view></router-view>
            </div>
            <script>
                let index = {template:"<h1>首页</h1>"}
                let account = {
                    data:function(){
                        return {
                            username:"zyb"
                        }
                    },
                    template:"<h1>我的账户</h1>",
                    beforeRouteEnter:function(to,from,next){
                    console.log('to',to),
                    console.log('from',from),
                    console.log(this.username),//访问不到
                    next(vm =>{
                        console.log("username:",vm.username);
                    })
                },  beforeRouteUpdate:function(to,from,next){
                    console.log('to',to),
                    console.log('from',from),
                    next()
                },
                    beforeRouteLeave(to,from,next){
                        let answer = window.confirm("要离开?")
                        if(answer){
                            next()
                        }
                    }
                }
                var router = new VueRouter({
                    routes:[
                        {path:"/",component:index,name:"index"},
                        {path:"/account/:userid",component:account,name:"account"},
                    ]
                })
                new Vue({
                    el:'#app',
                    router
                })
            </script>
        </body>
        </html>

*导航守卫执行的流程:
1.导航被触发
2.在失活的组件里调用离开守卫
3.调用全局的berofeEach守卫
4.在重用的组件里调用beforeRouteUpdate 守卫
5.在路由配置李调用
6.解析异步路由组件
7.在被激活的组件里调用
8.调用全局的beforeRouteLeave 守卫
9.导航被确认
10.调用全局的beforeEach 钩子
11.触发 DOM更新
12.用创建好的实例调用beforeRouteEnter 守卫中传给next 的回调函数

原文地址:https://www.cnblogs.com/Mr-Simple001/p/12106410.html