阅读 623

Vue-router

路由的基本概念与原理

路由介绍

  • 路由是一个比较广义和抽象的概念,路由的本质就是一一对应关系

  • 开发中路由分两种

    • 前端路由
    • 后端路由
  • 路由的本质就是一种对应关系,比如:在地址栏中输入url地址,获取对应的url资源

  • 路由分为前端路由和后端路由

    • 前端路由是依靠hash值(也就是a标签的锚点连接)的变化进行实现(锚点与组件之间的关系)
    • 前端路由的基本概念:根据不同的事件来显示不同的页面内容,事件与事件处理函数之间的对应关系
    • 前端路由主要做的事情就是监听事件,执行对应的事件处理函数
    • 后端路由是由服务器端实现的,并完成资源的分发(url与资源数据的对应关系)
    • 后端路由性能相对前端路由来说较低

后端路由

  • 后端路由介绍

后端路由

  • 总结

    • 后端 渲染页面,只要修改一处,就需要刷新整个页面,存在性能问题
    • Ajax是一种局部更新网页的技术,但是不支持前进后退

前端 路由

  • 前端路由介绍

    前端路由

    • 根据地址栏的变化(不发送Ajax请求),去局部更新页面内容
    • 前端业务场景切换
  • 前端-实现原理

    • 地址栏中的 #有两个含义

      • 锚点链接:在当前页面进行页面跳转

      • 哈希值(hash)的作用,当它发生变化时不会刷新当前页面,但是它的变化会触发hashchange事件,

        核心实现依靠hashchang事件,即监听hash值变化的事件

        window.onhashchange = function(){
            //location.hash可以获取到最新的hash值
            location.hash
        }
        复制代码
  • 总结

    • 路由:一种一一对应关系,请求url地址与url资源的一一对应
    • 后端路由:url与服务资源的一一对应关系
    • 前端路由:用户事件与事件处理函数的一一对应关系 比如点击页面的按钮改变url的hash值,根据hash值的变化来切换组件

SPA

  • SPA介绍

    • 单页面应用程序,简称SPA(single page application)一个项目的所有功能在一个页面上实现,(在移动端比较多,只要是用Vue开发的项目,绝大多数是SPA)
    • SPA实现原理之一:基于URL地址的hash值(hash的变化会导致浏览器记录访问历史的变化 ,但是hash的变化不会触发新的url请求)
    • SPA是通过前端路由实现业务场景的切换的。
    • SPA可以局部更新,也支持前进后退
    • 使用vue-router可以轻易的实现前端路由业务
  • 特点

    • 优点: 整体不刷新页面,用户体验更好
    • 缺点:首次加载会比较慢一点,后面会有优化的方式

Vue-router的基本使用

  • 介绍

    • Vue.js官方提供了路由管理器,是一个功能强大的前端路由器,推荐使用
    • Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发
    • vue Router依赖vue.js,必须先引入vue.js再引入vue Router
    • Vue Router 官网 router.vuejs.org/zh/
  • Vue Router的特性

    • 支持H5历史模式或者hash模式
    • 支持嵌路由
    • 支持路由参数
    • 支持编程式路由
    • 支持命名路由
    • 导航守卫
    • 路由懒加载
    • 过渡动效
    • ................

使用步骤

  • 引入 Vue router 文件( 在此之前必须先引入 vue.js文件)

  • 添加路由链接

  • 添加路由点位符(最后路由展示的组件就会在点位符的位置显示 )

  • 定义路由组件

  • 配置路由规则并创建路由实例

  • 将路由挂载到Vue实例中

  • 引入Vue router

        <!-- 导入vue文件,为全局window对象挂载Vue构造函数 -->
         <script src="./lib/vue_2.5.22.js"></script>
        <!-- 导入vue-router文件,为全局window对象挂载VueRouter构造函数 -->
        <script src="./lib/vue-router_3.0.2.js"></script>
    复制代码
  • 添加路由连接

     <!--router-link是路由提供的标签,默认会被渲染为a标签-->
     <!--to属性默认被渲染为href属性-->
     <!--to属性的值会被渲染为#开头的hash地址-->
    <router-link to="/user">User</router-link>
    复制代码
  • 添加路由占位符

    <!--将来通过路由规则匹配到的组件,将会被渲染到router-view所在的位置-->
    <router-view></router-view>
    复制代码
    • router-view:路由-视图,用户点击路由链接显示对应的组件
  • 定义路由组件

    var User = { template:"<div>This is User</div>" }
    var Login = { template:"<div>This is Login</div>" }
    复制代码
  • 创建路由实例,并配置路由规则

    //创建路由实例对象
    var router = new VueRouter({
        //routes是路由规则数组
        routes:[
            //每一个路由规则都是一个对象,对象中至少包含path和component两个属性
            //path表示  路由匹配的hash地址,
            //component表示路由规则对应要展示的组件对象
            {path:"/user",component:User},
            {path:"/login",component:Login}
        ]
    })
    复制代码
  • 将路由挂载到Vue实例中

    //将路由挂载到Vue实例中
    new Vue({
        el:"#app",
        //为了让路由规则生效,必须把路由对象挂载到Vue实例上
        router
    })
    复制代码
    • Vue实例化时参数el,data,methods,router都是固定的

路由重定向

  • 路由重定向指的是:用户在访问地址A的时候,强制用户跳转到地址c,从而展示特定的组件页面:通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向

    var router = new VueRouter({
        //routes是路由规则数组
        routes: [
            //path设置为/表示页面最初始的地址 / ,redirect表示要被重定向的新地址,设置为一个路由即可
            { path:"/",redirect:"/user"},
            { path: "/user", component: User },
            { path: "/login", component: Login }
        ]
    })
    复制代码
    • 应用:打开页面时默认访问的是#/根地址,我希望打开页面就能访问:#/user,所以使用重写向

路由-404页面

  • 当我们访问一个不存在的页面,给出一个提示,让用户访问404页面

  • 思路:其它的路由规则都没有匹配成功,用 * 来匹配保底

  • 格式: { path: '*', component: { template: '<div>你要找的页面,被外星人吃掉了~~~</div>' } }

    const router = new VueRouter({
            // routes: 配置路由规则
            routes: [
              // * 表示全部 , 实现404页
              // 其它规则都没有匹配成功,就到这里来
              { path: '*', component: { template: '<div>你要找的页面,被外星人吃掉了              ~~~</div>' }
              }
            ]
          })
    复制代码

嵌套路由

  • 点击父级路由链接显示模板内容,模板内容中又有子路由,点击子路由显示对应的内容

  • 比如我们有一个Login的父路由可以添加子路由/login/account与/login/phone

    <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" />
        <title>Document</title>
        <!-- 导入 vue 文件 -->
        <script src="./lib/vue_2.5.22.js"></script>
        <script src="./lib/vue-router_3.0.2.js"></script>
      </head>
      <body>
        <!-- 被 vm 实例所控制的区域 -->
        <div id="app">
          <router-link to="/user">User</router-link>
          <router-link to="/register">Register</router-link>
    
          <!-- 路由占位符 -->
          <router-view></router-view>
        </div>
    
        <script>
          const User = {
            template: '<h1>User 组件</h1>'
          }
    
          const Register = {
            template: `<div>
              <h1>Register 组件</h1>
              <hr/>
    
              <!-- 子路由链接 -->
              <router-link to="/register/tab1">tab1</router-link>
              <router-link to="/register/tab2">tab2</router-link>
    
              <!-- 子路由的占位符 -->
              <router-view />
            <div>`
          }
           //定义两个子级路由组件
          const Tab1 = {
            template: '<h3>tab1 子组件</h3>'
          }
    
          const Tab2 = {
            template: '<h3>tab2 子组件</h3>'
          }
    
          // 创建路由实例对象
          const router = new VueRouter({
            // 所有的路由规则
            routes: [
              { path: '/', redirect: '/user'},
              { path: '/user', component: User },
              // children 数组表示子路由规则
              { path: '/register', component: Register, children: [
                { path: '/register/tab1', component: Tab1 },
                { path: '/register/tab2', component: Tab2 }
              ] }
            ]
          })
    
          // 创建 vm 实例对象
          const vm = new Vue({
            // 指定控制的区域
            el: '#app',
            data: {},
            // 挂载路由实例对象
            // router: router
            router
          })
        </script>
      </body>
    复制代码
  • 总结

    • 子路由规则在父路由规则中定义,router-view和router-link就写在父路由模板中

vue-router动态路由匹配

动态路由匹配

  • 应用场景:通过动态路由参数的模式进行路由匹配

    <body>
        <!-- 被 vm 实例所控制的区域 -->
        <div id="app">
          <router-link to="/user/1">User1</router-link>
          <router-link to="/user/2">User2</router-link>
          <router-link to="/user/3">User3</router-link>
          <router-link to="/register">Register</router-link>
          <!-- 路由占位符 -->
          <router-view></router-view>
        </div>
    
     <script>
         //组件
        const User={
      //路由组件中通过$route.params获取路由参数
         template:'<div>用户:{{$route.params.id}}</div>'
      }
    
        var router = new VueRouter({
            //routes是路由规则数组
            routes: [
                //通过/:参数名的形式传递参数 
                { path: "/user/:id", component: User },
               ]
            })
        
        // 创建 vm 实例对象
        const vm = new Vue({
            // 指定控制的区域
            el: '#app',
            data: {},
            // 挂载路由实例对象
            // router: router
            router
        })
       </script>
     </body>
    复制代码
    • 匹配规则定义时,动态路由语法为**:参数名**,以冒号开头,就代表是动态匹配

    • 路由组件定义时,获取路由参数为:{{$route.params.参数名}}

    • 动态获取路由参数{{$route.params.}}是固定写法

props传递参数

  • 介绍props

    • $route.params与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦
    • props的使用分三类 :props的值为,布尔类型,对象类型,函数类型
  • props的值为布尔类型

    var User = { 
        props:["id"],  //使用props 接收路由参数
        template:"<div>用户:{{id}}</div>"  //使用路由参数
        }
    
    var myRouter = new VueRouter({
        //routes是路由规则数组
        routes: [
            //通过/:参数名  的形式传递参数 
            //如果props设置为true,route.params将会被设置为组件属性
            { path: "/user/:id", component: User,props:true },
        ]        
    复制代码
    • 路由定义规则中:props:true,true代表开启props传递动态参数
    • 路由组件定义中:通过props接收参数
  • props的值为对象类型

    var User = { 
        props:["username","pwd"],
        template:"<div>用户:{{username}}---{{pwd}}</div>"
        }
    
    var myRouter = new VueRouter({
        //routes是路由规则数组
        routes: [
            //通过/:参数名  的形式传递参数 
            //如果props设置为对象,则传递的是对象中的数据给组件
            { path: "/user/:id", component: User,
              props:{username:"jack",pwd:123}
             }
        ]
      })      
    复制代码
    • username的jacki传递给User组件中props的username,pwd的123传递给User组件中props的pwd
    • 这时的id就无法获取了,所以id在这种方式中就废了
    • 只有props为true时,才会将:id作为参数传递给User
  • props的值为函数类型

    var User = { 
        props:["username","pwd","id"],
        template:"<div>用户:{{id}} -> {{username}}---{{pwd}}</div>"
        }
    
    var myRouter = new VueRouter({
        //routes是路由规则数组
        routes: [
            //通过/:参数名  的形式传递参数 
            //如果props设置为函数,则通过函数的第一个参数获取路由对象
            //并可以通过路由对象的params属性获取传递的参数
    
            { path: "/user/:id", component: User,
               props:route=>{
                return {username:"jack",pwd:123,id:route.params.id}
                } 
            }
        ]
    })
    复制代码
    • 箭头函数返回一个对象,对象中的数据就是要传递的数据
    • id通过 route.params.id动态获取到id参数的值

query查询传参

  • 查询传参 :this.$router.query.id

     //参数 id=1&age=3
    <router-link to="/user?id=1&age=3">query查询传参</router-link>
    
    var User = {     // $route.query获取的是一个对象 ,在路由链接中查询参数
        template: `  <div> {{$route.query.id}} - {{$route.query.age}}</div>`
        }
    
    var myRouter = new VueRouter({
        //routes是路由规则数组
        routes: [
            { path: "/user", component: User }
        ]
    })
    
    复制代码

命名路由与编程式导航

###命名路由

  • 为了更加方便的表示路由的路径,可以给路由规则 起一个别名,即为 “命名路由”
  //路由链接
<router-link :to="{ name:'user' , params: {id:123} }">User</router-link>

const router = new VueRouter({
    //routes是路由规则数组
    routes: [
        //通过name属性为路由添加一个别名
        { 
            path: "/user/:id",
            component: User,
            name:"user"  //命名路由
        },
    ]
})
复制代码
  • 有时候path比较复杂,用命名路由代替会更好一点
  • 如果path中有参数,那么在to中就通过params来确定参数的值

编程式导航

  • 页面导航的两种方式

    • 声明式导航:通过点击链接实现导航的方式,叫做声明式导航

      例如 普通网页中的<a></a>链接或vue中的<router-link></router-link>

    • 编程式导航:通过调用javaScript形式的APl实现导航的方式,叫做编程式导航

      例如:普通网页中的location.href

      • 声明式导航:其实就是html实现导航
      • 编程式导航:其实就是js代码实现导航(location.href 就是js代码)
      • 编程式路由跳转:this.$router.push("/register")
  • 编程导航

    • 常用的编程式导航API

      this.$router.push(hash地址)  //根据hash值跳转到对应的组件上
      this.$router.go(n)      // 前进后退功能 n表示数值 '-1'后退 '1' 前进 
      复制代码
      cons User={
       template:'<div><button @click="goRegister">跳转到注册页面</button></div>'
       methods:{
         goRegister:function(){
          //用编程的方式控制路由跳转
          this.$router.push("/register");
         }
        }
      }
      复制代码
      • push跳转锚点
      • go前进后退,参数n一个数字,代表前进后退几个界面
        • n,代表前进n个界面
        • -n,代表后退n个界面

push参数 (了解)

  • 介绍

    push参数

  • 跟route-link是一样的作用,都是实现页面跳转

  • 所以push中可以直接写path路径(路由),也可以写命名路由

  • 相当于:

    <!--前两个对应这个  -->
    <router-link to="/home">User1</router-link>
    <!--#push中的name应该也不带斜杠才对-->
    <!--命名路由(传递参数)-->
    <router-link :to="{ name: 'user', params: {userId: 123} }">User123</router-link>
    <!--带查询参数,变成 register?uname=lisi -->
    <router-link to="/register?uname=lisi">Register</router-link>
    复制代码

导航守卫

  • 在路由跳转之后加一层拦截做一些我们自己的事

  • 实际应用场景:登录

    • 如果当前登录了,我就让你跳到列表页l 如果没登录 那我就提示你登录,并且不让你跳转 特点:在发生路由跳转行为的时候,会调用回调函数 这个就是导航守卫
    router.beforeEach((to, from, next) => {
      console.log('当前路由跳转了')
      next()
    })
    //  to: 代表的是目标路由对象   detail路由对象
    //  from: 代表的是路由跳转的来源对象   list路由对象
    //  next: next函数的执行决定了能不能跳转  如果不调用会产生一种 ‘守死了’
      
    // 模拟登陆校验
    const loginFlag = false
    router.beforeEach((to, from, next) => {
      // 判断当前是否登录  loginFlag true 登录   false 没登录
      if (!loginFlag) {
        // 如果没登录就提示登录
        alert('请先登录!')
      } else {
        // 如果登录了就跳转
        next()
      }
    })
    复制代码

「点赞、收藏和评论」

❤️关注+点赞+收藏+评论+转发❤️,鼓励笔者创作更好的文章,谢谢🙏大家。

文章分类
前端
文章标签