Router

作者: 羊烊羴 | 来源:发表于2017-10-19 15:16 被阅读0次

    路由

    <body>
    <div id="box">
        <div>
            <router-link to="/home">Home</router-link>
            <!--router-link用来展示组件导航-->
            <!--to属性用于指定链接-->
            <!--<router-link>标签会默认被渲染成a标签-->
            <!--当前被点击的路由会自带.router-link-active属性-->
            <router-link to="/news">News</router-link>
        </div>
        <div>
            <!--路由出口,路由默认会被渲染在这里-->
            <router-view></router-view>
        </div>
    </div>
    </body>
    <script>
        //创建路由组件
        var Home = {
                template: "<h4>我是主页</h4>"
            },
            News = {
                template: "<h4>我是新闻</h4>"
            };
        //定义组件
        var routes=[
            {path:"/home",component:Home},
            {path:"/news",component:News},
            {path:"*",redirect:"/home"}
        ]
        //创建路由实例,配置路由实例
        var router=new VueRouter({
            routes:routes,
            linkActiveClass:"color"
        })
        //创建并将路由挂载到根实例
        new Vue({
            el:"#box",
            router:router
        })
    </script>
    
    动态路由匹配

    我们经常需要把某种模式匹配到的所有路由,全部映射到同一个组件,例如我们有一个user组件用来展示用户信息,那么对于不同ID的用户,我们都需要使用这个组件来渲染,那么我们就可以在vue-router的路由路劲中使用动态路径参数来达到这个效果

    body>
    <div id="box">
        <div>
            <router-link to="/home/1">Home</router-link>
            <router-link to="/home/2">News</router-link>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
    <template id="home">
        <div>
            <h4>this's homr</h4>
        </div>
    </template>
    <template id="news">
        <div>
            <h4>this's news</h4>
        </div>
    </template>
    <script>
        var Home = {
                template: "#home"
            },
            News = {
                template: "#news"
            };
        var routes=[
            {path:"/home/:id",component:Home},
            {path:"/news",component:News}
        ];
       //在routes中路径参数使用:标记,那么在匹配路由时,所有 /home/参数  格式的路径都会被匹配到Home组件,当然也可以同时使用一个或多个 例如 /home/:id/name/:id  路径参数使用:标记那么表示这个参数可以是任意值,:id的作用只是一个占位符,也可以使用正则来匹配,如:/:id(\\d+)
        var router=new VueRouter({
            routes:routes
        });
        new Vue({
            el:"#box",
            router:router
        })
        
    //在路由中设置多段路径参数,对应的值都会设置到$route.params中,例如:
    //   /user/:username匹配到路径/user/tom,那么我们可以通过$router.params获取到{username:"tom"}
    </script>
    </body>
    

    当我们使用路由参数时,例如从/user/foo跳转到/user/bar时,原来的组件会被复用,这样更加高效,但是同时也意味着组件的生命周期函数不是再被调用,如果想要对路由参数的变化做出响应的话,可以所使用watch监测$route对象

    <script>
    var User = {
                template: "#user",
                watch:{
                    '$route'(to,from){
                        console.log(to);
                        console.log(from);
                        //to表示从哪个路由开始跳转
                        //from表示跳转到哪个路由
                        //在跳转时会触发$route函数
                    }
                }
            }
    </script>
    
    路由嵌套

    实例一

    <body>
    <div id="box">
        <div>
            <router-link to="/home">Home</router-link>
            <router-link to="/news">News</router-link>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
    <template id="home">
        <div>
            <h4>this's home</h4>
            <ul>
                <li>
                    <router-link to="/home/tom">Tom</router-link>
                    <router-link to="/home/aix">Aix</router-link>
                </li>
                <li>
                    <router-view></router-view>
                </li>
            </ul>
        </div>
    </template>
    <template id="news">
        <div>
            <h4>this's news</h4>
        </div>
    </template>
    
    <script>
        var Home = {
                template:"#home"
            },
            News = {
                template: "#news"
            },
            Tom={
                template:`
                    <p>my name's tom</p>
                `
            },
            Aix={
                template:`
                    <p>my name's aix</p>
                `
            };
        var routes=[
            {
                path:"/home",
                component:Home,
                children:[
                    {
                        path:"tom",
                        component:Tom
                    },
                    {
                      path:"aix",
                        component:Aix
                    }
                ]
            },
            {path:"/news",component:News}
        ]
    
        var router=new VueRouter({
            routes
        })
    
        new Vue({
            router
        }).$mount("#box")
    </script>
    </body>
    

    实例二

    <body>
    <div id="box">
        <div>
            <h5>
                <router-link to="/user/foo">A</router-link>
                <router-link to="/user/foo/bar">B</router-link>
                <router-link to="/user/foo/cat">C</router-link>
            </h5>
            <router-view></router-view>
        </div>
    </div>
    <script>
        const User = {
            template: `
            <div>
                <p>{{$route.params.id}}</p>
                <router-view></router-view>
            </div>
            `
        }
        const userHome = {
            template: `
            <div>Home</div>
        `
        }
        const bar = {
            template: `
            <div>A</div>
            `
        }
        const cat = {
            template: `
                <div>
                     <div>{{$route.matched}}</div>
                     <div>B</div>
                </div>
           `
        }
        const router = new VueRouter({
            routes: [
                {
                    path: "/user/:id",
                    component: User,
                    children: [
                        {path: "", component: userHome},
                        {path: "bar", component: bar},
                        {path: "cat", component: cat}
                    ]
                }
            ]
    
        })
    
        new Vue({
            router
        }).$mount("#box")
    </script>
    </body>
    
    编程式导航

    在vue中我们除了使用<router-link>创建a标签来定义导航链接,还可以杰作router的实例方法,通过编写代码来实现,我们使用router-link标签时,实际在内部会调用router.push方法,所以说点击<router-link :to="/home">等同于调用router.push("/home")

    <body>
    <div id="box">
        <div>
            <li @click="home">Home</li>
            <li @click="news">News</li>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
    
    <script>
        const Home = {
            template: `
                    <div>
                        <h3>this's Home</h3>
                     </div>
                `
        };
        const News = {
            template: `
                    <div>
                        <h3>this's News</h3>
                    </div>
                `
        };
    
        const router = new VueRouter({
            routes: [
                {path: "/home", component: Home},
                {path: "/news", component: News}
            ]
        })
    
        new Vue({
            router,
            methods: {
                home() {
                    router.push("/home")
                },
                news() {
                    router.push("/news")
                }
            }
        }).$mount("#box")
    </script>
    </body>
    
    • router.push()

      该方法回想histiry栈添加一个新的记录,所以当用户点击浏览器后退按钮时,会回到之前的URL

    • router.repalce()

      该方法和router.push相似,唯一不同在于,它不会向history添加新纪录,而是替换掉当前的history记录,所以用户不能点击浏览器后退按钮,该方法相当于<router-link :to="..." replace>

    • router.go(n)

      该方法的参数是一个整数,意思实在history记录中向前或者后退多扫不,类似window.history.go(n),如果浏览器history记录本身小于n,那么会失败,并且不会返回失败信息

    push以及replate的参数可以是一个字符串路径,或则一个描述的对象:

    //字符串
    router.push("/home")
    //对象
    router.push({psth:"/home"})
    //命名的路由
    router.push({name:"user",params:{userId:123}})
    //带查询参数,变成/register?plan=private
    router.push({path:'register',query:{plan:'private'}})
    
    命名路由

    有时候,通过一个名称来表示一个路由显的更方便一些,特别是在链接一个路由或执行一些跳转的时候,我们可以在创建Router实例的时候,在routers配置中给某个路由设置名称

    <body>
    <div id="box">
        <div>
            <router-link :to="{name:'home',params:{homeId:123}}">Hmoe</router-link>
            <!--params表示传入的动态路由homeId的参数123,该参数会传入到路由的url地址中-->
            <router-link :to="{name:'news'}">ews</router-link>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
    <script>
        const Home = {
                template: `
                <div>
                    <h5>this's Home</h5>
                </div>
            `
            },
            News = {
                template: `
                <div>
                    <h5>this's News</h5>
                </div>
            `
            };
    
        var router = new VueRouter({
            routes: [
                {
                    path: "/home/:homeId",
                    name: "home",
                  //在router中为路由设置名称后,在router-link中:to 直接接受路由名称即可
                    component: Home
                },
                {
                    path:"/news",
                    name:"news",
                    component:News
                }
            ]
        })
    
        new Vue({
          router
        }).$mount("#box")
    </script>
    </body>
    
    命名视图

    如果我们想要同时在统计展示多个视图,而不是嵌套展示,例如创建一个布局,有导航栏和主内容两个视图,我们可以使用命名视图,利用命名视图我们可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口,如果router-view标签没有设置名字,那么默认为default

    <style>
        .nav {
            width: 100%;
            height: 40px;
            color: forestgreen;
            }
        .main {
            width: 100%;
            height: 100px;
            color: forestgreen;
            border: 1px solid #000;
            }
    </style>
    </head>
    <body>
    <div id="box">
        <div>
            <router-link to="/nav">Nav</router-link>
            <router-link to="/main">Main</router-link>
        </div>
        <div>
            <router-view name="navView" class="nav"></router-view>
            <router-view name="mainView" class="main"></router-view>
        </div>
    </div>
    <script>
        const Nav = {
                template: `
                    <div>
                        <h5>this's nav</h5>
                    </div>
                `
            },
            Main = {
                template: `
                    <div>
                        <h5>this's main</h5>
                    </div>
                `
            };
        const router=new VueRouter({
            routes:[
                {
                    path:"/nav",
                    components:{
                        "navView":Nav
                    }
                },
                {
                    path:"/main",
                    components:{
                        "mainView":Main
                    }
                }
            ]
        })
        new Vue({
            router
        }).$mount("#box")
    </script>
    </body>
    
    重定向和别名

    重定向是指将当前路由的指向重新定位到其它路由上,使用redirect来实现

    const router=new VueRouter({
      routes:[
        {path:"/a",
        redirect:"/b"}
        //此时的/a的路由点击会被重定向到/b路由上
      ]
    })
    //一般我们使用重定向来进行初始化页面的展示
    { path:"*",redirect:"/b"}
    //重定向也可以传入一个路由名称
    {path:"/a",redirect:"{name:'b'}"}
    

    别名和重定向的大致作用是类似的,但是区别在与

    使用重定向时当用户访问/a时,匹配路由为/b,URL地址中也会被替换为/b

    使用别名时当用户访问/a时,匹配的路由为/b,但是URL地址中不会被替换,依然是/a,就像用户访问/a一样

    const router=new VueRouter({
      routes:[
        path:"/a",
        alias:"/b"
      ]
    })
    
    导航钩子

    vue-router提供了导航钩子主要用来拦截导航,或则完成跳转或取消,vue-router的导航钩子会在路由发生改变时执行,有多种方式可以在路由发生改变时执行钩子:全局的,单个路由独享的,或者是组件级的

    • 全局钩子

      使用router.beforeEach注册一个全局的before钩子

      const router=new VueRouter({...})
      router.beforeEach((to,form,next)=>{
        .....
      })
      

      当一个导航触发时,全局的before钩子会按照创建顺序调用,钩子是异步解析执行,此时导航在所有钩子执行完之前一直处于等待中

      每个钩子接收三个参数:

      • to 表示将要进入的目标路由对象
      • form 表示当前导航将要离开的路由
      • next 如果了解node的话可以理解为node中的next()中间件,next()表示进行下一个导航,next(false)表示中断当前的导航,也就是不再执行下一个跳转导航的操作,next("/")或者next({path:"/",...})表示跳转到我们指定的导航

      一定要注意,一定要调用next()方法,否则之后的操作都不会被执行

      同样可以注册一个全局的after钩子,不过它没有next方法,不能改变导航

      router.afterEach(function (to,form) {
        console.log(to);
        console.log(form);
        alert("离开"+form.fullPath+",进入"+to.fullPath);
      })
      
    • 单个路由的钩子

      通过为单个路由设置beforeEnter方法,该方法接收的参数和beforeEach是一样的

       const router = new VueRouter({
              routes: [
                  {
                      path: "/home",
                      component: Home,
                      children: [
                          {
                              path: "info",
                              component: Info,
                              meta: { requiresAuth: true,age:18 },
                              beforeEnter:function (to,form,next){
                                  console.log(to);
                                  console.log(form);
                                  next();
                              }
                          },
                          {path: "set", component: Set}
                      ]
                  },
                  {path: "/news", component: News}
              ]
          })
      

      同样需要注意一定调用next(),否则不会进入到该导航

    • 组件内的钩子

      也可以在路由组件内直接定义导航钩子

      • beforeRouteEnter
      • beforeRouteUpdata(2.2)
      • beforeRouteLeave
     News = {
                template: `
                <div>
                    <h4>this's News</h4>
                </div>
            `,
                data() {
                    return {
                        msg: 1
                    }
                },
                beforeRouteEnter: function (to, form, next) {
                    //注意在这里不能调用实例的this,因为该方法是在组件被创建之前调用的,所以此时实例是不存在的
                    next(vm => {
                        console.log(vm.$data.msg);
                    });
                    //但是可以通过为next传入一个回调,把组件实例作为回调参数的方法来访问组件的实例
                },
                beforeRouteUpdate:function (to,form,next) {
                    //该方法只有在当前组件被复用时会调用
                    //例如,对于一个带有动态参数的路径,foo/:id,在foo/1和foo/2之间跳转的时候
                    //由于会渲染同样的foo组件,因此逐渐实例会被复用,而这个钩子会被调用,类似动态组件中的watch
                    //可以访问实例的this
                },
                beforeRouteLeave:function(to,form,next) {
                    //在导航离开组件的对应路由时调用
                    //可以访问组件实例this
                    //这个钩子通常用于在用户还未保存修改钱突然离开,可以通过next(false)来取消导航
                }
            }
    
    路由元信息

    定义路由的时候可以定义路由的meta字段,在meta中定义的字段,可以在路由记录中获取,可以用来对对每个路由进行配置,在vue中,我们称呼router配置中的每个路由对象为路由记录,路由记录可以是嵌套的,因此,当一个路由匹配成功后,它可能匹配多个路由记录,例如我们匹配到/foo/bar这个URL将会匹配副路由记录以及自路由记录,一个路由匹配到的所有路由记录会暴露为$route.matched数组,因此,我们可以遍历$$router.matched来检查路由记录中的meta字段

      const router = new VueRouter({
        routes: [
                {
                   path: "/home",
                      component: Home,
                      children: [
                          {
                              path: "info",
                              component: Info,
                              meta: {
                                  requiresAuth: true,
                                  title:"主页"
                              }
                          },
                          {path: "set", component: Set}
                      ]
                  },
                  {path: "/news", component: News}
              ]
        })
      ...........
    
      router.beforeEach((to,form,next)=>{
        if(to.matched.some(record => record.meta.requiresAuth)){
            //if的判断条件是用来判断meta中设置的requiresAuth变量是否为true
            //可以用来判断该页面是否需要用户登录才能进入该页面
            //如果我们设置一个路由的meta中requiresAuth变量为true,在全局路由钩子函数执行的时候都会进入if判断
            console.log(to.matched.some(record => record.meta.requiresAuth));//true
            //meta中设置的值也可以用来保存该路由中的信息,例如在meta中设置title属性和值,在进入该页面的时候获取该title值设置到页面中等操作
                 document.getElementById("test").innerText=to.meta.title;
            if(用户没有登录){
                next("/login"); //跳转到登录页面
            }else {
                next()
            }
        }else{
            next()
              //如果该页面不需要登录操作,执行用户操作
        }
      })
    

    注意,在to和form中我们可以获取到跳转的路由的信息,下面是打印的to的信息:

    {name: undefined, meta: {…}, path: "/home/info", hash: "", query: {…}, …}

    滚动行为

    使用前端路由,当我们切换到新路由时,想要页面滚动到顶部,或者是保持原先的滚动位置,就像重新加载页面那样,vue-router提供了更好的方法来让自定义路由切换页面是如何滚动

    注意,这个功能只在HTML5 history模式下可用

    在创建一个router实例的时候,可以提供一个scrollBehavior方法,该方法会在用户进行路由切换时触发

    const router=new VueRouter({
            routes:[
                {
                    path:"/",
                    component:Home
                }
            ],
            scrollBehavior(to,form,savedPosition){
            //scrollBehavior方法接收to,form路由对象,第三个参数savedPosition当且仅当在浏览器前进后退按钮触发时才可用
            //该方法会返回滚动位置的对象信息,如果返回一个布尔假肢,或者是一个空的对象,那么不会发生滚动
            //我们可以在该方法中设置返回值来指定页面的滚动位置,例如:
             return {x:0,y:0}
            //表示在用户切换路由时让是所有页面都返回到顶部位置
            //如果返回savedPosition,那么在点击后退按钮时就会表现的像原生浏览器一样,返回的页面会滚动过到之前按钮点击跳转的位置,大概写法如下:
             if(savedPosition){
                return savedPosition
             }else{
               return {x:0,y:0}
             }
             //如果想要模拟滚动到锚点的行为:
             if(to.hash){
               return {
                 selector:to.hash
               }
             }
         }
    })
    
    router-link属性
    • to

      表示目标路由的链接,当被点击时,内部会立刻把to的值传到router.push(),通过to传递的链接会被保存在history记录中,所以可以使用浏览器回退

    • replace

      如果设置replace属性的话,当路由被点击时,会调用router.replace(),本次操作不会留下history记录

      <router-link to="/home" replace></router-link>
      
    • append

      在设置append属性后,则表示正在当前相对路径前添加路径,例如我们是从/a导航到/b,那么在设置了append属性后路由导航会跳转到/a/b,而不是/b

      <router-link to="a" append>a</router-link>  //注意不要写/a的形式
      
    • tag

      如果想要把router-link渲染成除a外的其它标签,可以使用tag来指定渲染之后应该是哪种标签,同样他还是会监听点击,触发导航

      <router-link to="/home" tag="li"></router-link>
      
    • exact

      表示是否激活全局,可以理解为如果一个导航的路径是/home开头的,并且我们设置了点击样式,在/home路径的导航设置了exact的情况下所有以、home开头的路径的导航的样式都会同时改变

      https://jsfiddle.net/8xrk1n9f/ 这是vue官方的一个简单直观的例子

    • 将激活时的css类名应用在外层元素

      有时候我们需要让css类应用在外层元素,而不是a标签本身,那么可以用router-link渲染外层元素,包裹着内层原生a标签

      <router-link tag="li" to="/home">
        <a>Home</a>
      </router-link>
      

      这种情况下,a将作为真实的链接,它会获得正确的href,而激活时的css类名则会设置到外层的li

    • events
      用来可以用来触发导航的事件,默认是"click"

    router-view属性
    • name
      如果 <router-view>设置了名称,则会渲染对应的路由配置中 components 下的相应组件

    相关文章

      网友评论

          本文标题:Router

          本文链接:https://www.haomeiwen.com/subject/mswuuxtx.html