2021-06-21前端路由-第五天

一、 路由

1. 什么是路由

(1)路由就是一种映射关系。
(2)后端路由:url与后端资源的一 一对应的关系
(3)前端路由:用户事件与事件处理函数一 一对应的关系

2.实现简易前端路由

(1)前端路由是基于hash值的变化实现的,这里的hash值指的是 url的hash值,也就是界面的锚点。
(2)比如点击页面中的菜单或者按钮改变URL的hash值,根据hash值的变化来控制组件的切换。
(3)核心实现依靠 window.onhashchange 事件,监听hash值的变化。location.hash 可以获取到最新的hash值。

window.onhashchange = function(){
location.hash
}

(4)<component> 标签相当于一个组件调用的占位符。通过绑定 v-bind:is 属性,动态控制此处调用哪个组件。 (重点)
这个标签再父组件调用子组件时也可以用。

<component :is="comName"></component>

    <div class="box">
      <a href="#yule">娱乐</a>
      <a href="#caijing">财经</a>
      <a href="#keji ">科技</a>
      <a href="#junshi">军事</a>

      <component v-bind:is="change"></component>
    </div>

    <script>
      // 子组件
      var yule = {
        template: `<h1>娱乐头条</h1>`,
      };
      var caijing = {
        template: `<h1>财经频道</h1>`,
      };
      var keji = {
        template: `<h1>科技在线</h1>`,
      };
      var junshi = {
        template: `<h1>军事理论</h1>`,
      };

      // vue实例对象--父组件
      var vm = new Vue({
        el: '.box',
        data: {
          change: 'yule',
        },
        components: {
          yule: yule,
          caijing: caijing,
          keji: keji,
          junshi: junshi,
        },
      });

      // 监听页面的hash值的变化
      window.onhashchange = function () {
        var x = location.hash.slice(1);
        switch (x) {
          case 'keji':
            vm.change = 'keji';
            break;
          case 'yule':
            vm.change = 'yule';
            break;
          case 'caijing':
            vm.change = 'caijing';
            break;
          case 'junshi':
            vm.change = 'junshi';
            break;
        }
      };
    </script>

二、 vue-router

vue-router官网:https://router.vuejs.org/zh/

1. 什么是 vue-router

① 它是一个Vue.js官方提供的路由管理器。
② Vue Router和Vue.js非常契合,可以一起方便的实现SPA(single page web application,单页应用程序)应用程序的开发
③ Vue Router依赖于Vue,所以需要先引入Vue.js,再引入Vue Router.js

2. Vue Router的特性
  • 支持H5历史模式或者hash模式
  • 支持嵌套路由
  • 支持路由参数
  • 支持编程式路由
  • 支持命名路由
3. 路由的基本使用

① 导入js文件。(项目中用import关键字引入)
必须先引入vue.js,再引入vue-router.js。

   <!-- 1. 引入文件 -->
    <script src="js/vue_2.5.22.js"></script>
    <script src="js/vue-router_3.0.2.js"></script>

② 添加 路由链接。(项目中多用编程式导航)

      <!-- 2. 添加路由链接 -->
      <!-- 整个标签会被渲染成a链接。 -->
      <router-link to="/user">User</router-link>
      <router-link to="/register">Register</router-link>

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

      <!-- 3.添加路由占位符 -->
      <!-- 将来通过路由规则匹配到的组件,会被渲染到这里 -->
      <router-view></router-view>

④ 定义 路由组件(项目中每个.vue文件都是组件)

  • 路由组件全局定义,不需要使用 Vue.component,也不用再vue实例对象中挂载。
  • 路由组件中的data 数据格式为:data( ) { return { } }
  • 需要在vue实例对象中挂载 路由实例对象
    // 4.创建路由组件
      const User = {
      data() { 
        return { name: "吴磊" }
      },
        template: `<h1>user</h1>`,
      };
      const Register = {
        template: `<h1>register</h1>`,
      };

⑤ 创建路由实例并配置 路由规则。(项目中将这部分单独写到一个.js文件)

  • 路由规则【routes】是一个数组,每个数组元素都是一个配置对象。
  • 每个配置对象至少有两个属性:path 、component。
  • path的值是路由链接的hash值;component的值是路由组件的名称。(不能加引号)
      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        // 路由规则【routes】是一个数组,每个数组元素都是一个配置对象。
        // 每个配置对象至少有两个属性:path 、component。
        // path的值是路由链接的hash值;component的值是路由组件的名称。(不能加引号)
        routes: [
          { path: '/user', component: User },
          { path: '/register', component: Register },
        ],
      });

⑥ 将路由挂载到Vue实例对象中

      // 6. 将路由挂载到vue实例对象中
      var vm = new Vue({
        el: '.box',
        router: router,
      });

⑦ 如果 是在项目中,应该全局注册路由,这样在任何一个vue组件 中都能使用this.$router

Vue.use(VueRouter)

示例如下:

   <div class="box">
      <!-- 2. 添加路由链接 -->
      <!-- 整个标签会被渲染成a链接。 -->
      <router-link to="/user">User</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 3.添加路由占位符 -->
      <!-- 将来通过路由规则匹配到的组件,会被渲染到这里 -->
      <router-view></router-view>
    </div>

    <script>
      // 4.创建路由组件
      const User = {
        template: `<h1>user</h1>`,
      };
      const Register = {
        template: `<h1>register</h1>`,
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        // 路由规则【routes】是一个数组,每个数组元素都是一个配置对象。
        // 每个配置对象至少有两个属性:path 、component。
        // path的值是路由链接的hash值;component的值是路由组件的名称。(不能加引号)
        routes: [
          { path: '/user', component: User },
          { path: '/register', component: Register },
        ],
      });

      // 6. 将路由挂载到vue实例对象中
      var vm = new Vue({
        el: '.box',
        router: router,
      });
    </script>

三、路由的更多使用规则

1. 路由重定向

{ path: '/', redirect: '/user' }

在路由规则中,使用 redirect 属性,可以实现路由重定向。当访问 " / " 根路径时,强制跳转到 " /user " 页面。

注意:
① 如果重定向的是一个子路由,则该路由的父级路由组件也会被渲染出来。
② 子路由可以把path属性设置为空,父路由组件渲染时默认显示这个子路由组件。

2 .路由嵌套

① 子路由的 路由链接路由占位符 ,写到父级路由的组件模板中。
② 子路由的 组件 直接全局定义。
③ 子路由的 路由规则数组 ,写到父级路由的规则配置对象中。

注意:
① 一级父路由的路径以 "/" 开头;
② 子路由的path路径可以带上父路由路径 /father/children
③ 也可以只写子路由路径,但是不能再以 / 开头。
④ 根路由已经挂载到vue实例对象上了,子组件不需要操作。

   <div class="box">
      <!-- 2. 父级路由链接 -->
      <router-link to="/user">User</router-link>

      <!-- 3.父级路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      // 4.父级路由组件
      const User = {
        template: `<div>
            <h1>user</h1>
            <router-link to="/user/table1">table1</router-link>
            <router-link to="/user/table2">table2</router-link>

            <router-view></router-view>
         </div>`,
      };
      // 子级路由组件
      const child1 = {
        template: '<h3>table1</h3>',
      };
      const child2 = {
        template: '<h3>table2</h3>',
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        routes: [
          {
            path: '/user',
            component: User,
            children: [
              { path: '/user/table1', component: child1 },
              { path: '/user/table2', component: child2 },
            ],
          },
        ],
      });

      // 6. 将路由挂载到vue实例对象中
      var vm = new Vue({
        el: '.box',
        router: router,
      });
    </script>
3. 动态匹配路由(重要)

① 如果多个路由链接的 hash值 非常相似,可以在 路由规则 中,让多个 path 值(路由链接的hash值) 对应一个componet (路由组件)。
② 也就是 多个路由链接 对应一个 路由规则

<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>

routes: [{ path: '/user/:uid?', component: User }],
动态参数uid后面的 表示,访问也面时,这个动态参数可以传递,也可以不传递。

实例:不同频道有各自的文章列表数据,我们根据频道的id生成了多个组件去渲染数据。如果想要用路由跳转到各个组件页面,就要用动态路由。否则多个频道对应对个组件,就要定义多个路由。

4. 动态匹配路由传参(重要)
  • 路由规则对象路由组件 传递参数。

(1)路由组件可以通过 $.route.params.uid 获得路由规则对象中的 动态参数 uid

template: "<h1>路由的id为{{$route.params.uid}}</h1>"

this.$route.query.id 可以获取路由规则中的查询参数

this.$router.options.routes 可以获得路由(规则)对象。

(2)在路由规则对象中,添加 props属性。props属性值为 true 时,路由组件可以通过 props数组 获得路由规则对象中的 动态参数 uid

     // 4.创建路由组件
      const User = {
        props: ['uid'],
        template: `<h1>路由的id为{{uid}}</h1>`,
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        // 在路由规则中,让多个路由链接对应一个路由组件。
        routes: [{ path: '/user/:uid', component: User, props: true }],
      });

(3)props属性值为 一个对象 时,路由组件可以通过 props数组 获得路由规则中的 静态参数

     // 4.创建路由组件
      const User = {
        props: ['uname','age'],
        template: `<h1>姓名:{{uname}},年龄:{{age}}</h1>`,
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        // 在路由规则中,让多个路由链接对应一个路由组件。
        routes: [
          {
            path: '/user/:uid',
            component: User,
            props: { uname: '吴磊', age: '22' },
          },
        ],
      });

(4)props属性值为 一个函数 时,路由组件可以通过 props数组 获得路由规则中的 静态参数和动态参数

     // 4.创建路由组件
      const User = {
        props: ['uname', 'age', 'uid'],
        template: `<h1>姓名:{{uname}},年龄:{{age}},id:{{uid}}</h1>`,
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        // 在路由规则中,让多个路由链接对应一个路由组件。
        routes: [
          {
            path: '/user/:uid',
            component: User,
           // 箭头函数只有一句代码,并且是返回值信息,则可以省略花括号。
            props: (route) => ({
              uname: '吴磊',
              age: '22',
              uid: route.params.uid,
            }),
          },
        ],
      });
5. 命名路由

① 在 路由规则对象 中,添加 name 属性,为这个路由规则命名。
② 在 路由链接 中,为 to属性绑定 一个对象, 代替 url地址

<router-link v-bind:to="{name:'user',params:{uid:3}}">User3</router-link>
routes: [
   {
     name: 'user',
     path: '/user/:uid',
     component: User,
   },
],

    <div class="box">
      <!-- 2. 路由链接 -->
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <!-- 命名路由 -->
      <router-link v-bind:to="{name:'user',params:{uid:3}}">User3</router-link>

      <!-- 3.添加路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      // 4.创建路由组件
      const User = {
        props: ['uname', 'age', 'uid'],
        template: `<h1>姓名:{{uname}},年龄:{{age}},id:{{uid}}</h1>`,
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        routes: [
          {
            // 命名路由
            name: 'user',
            path: '/user/:uid',
            component: User,
          },
        ],
      });

      // 6. 将路由挂载到vue实例对象中
      var vm = new Vue({
        el: '.box',
        router: router,
      });
6. 编程式导航

声明式导航:通过点击链接实现导航的方式,叫做声明式导航 例如:普通网页中的 链接 或 vue 中的 <router-link></router-link>
编程式导航:通过调用JavaScript形式的API实现导航的方式,叫做编程式导航 例如:普通网页中的 location.href
(1)常用的编程式导航的API

this.$router.push('hash地址') 跳转到指定页面

this.$router.go( ) 页面的前进与倒退

(2)push 方法可以接收的参数

router.push('/home') // 字符串(路径名称)
router.push({ path: '/home' }) // 对象
router.push({ name: 'user', params: { userId: 123 }}) // 命名的路由(传递参数)
router.push({ path: '/register', query: { uname: 'lisi' }}) // 带查询参数,变成 /register?uname=lisi

    <div class="box">
      <!-- 2. 路由链接 -->
      <router-link to="/user">User</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 3.添加路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      // 4.创建路由组件
      const User = {
        template: `<div>
          <h1>User部分</h1>
          <button v-on:click="handle">跳转到Register页面</button>
        </div>`,
        methods: {
          handle: function () {
            // 用编程的方式控制路由跳转
            this.$router.push('/register');
          },
        },
      };

      const Register = {
        template: `<div>
          <h1>Register部分</h1>
          <button v-on:click="handle">回退</button>
        </div>`,
        methods: {
          handle: function () {
            // 用编程的方式控制路由跳转
            this.$router.go(-1);
          },
        },
      };

      // 5. 创建路由实例并配置路由规则
      var router = new VueRouter({
        routes: [
          { path: '/user', component: User },
          { path: '/register', component: Register },
        ],
      });

      // 6. 将路由挂载到vue实例对象中
      var vm = new Vue({
        el: '.box',
        router: router,
      });
    </script>
7. 路由的导航守卫(重要)

作用:路由导航守卫可以判断当前状态下是否有token 令牌。从而限制用户直接输入地址访问页面。

(1)前置守卫

router.beforeEach(function(to, from, next) {}

to 代表要去的路由;
from 代表从哪个路由来;
next 是一个钩子函数,必须进行调用。

(2)后置守卫

router.afterEach(function() {})

注意:这里的router使用的是 路由的实例对象,也就是包含了路由规则的路由对象。

8. 路由的权限处理

(1)登录时路由权限处理(访问权限)

① 动态路由不要直接挂载到router实例对象上。

② 当前登录用户的个人信息里,有一个属性保存了当前用户的 权限标识,这个权限标识和 动态路由对象里的name属性值 一 一对应。

③ 动态路由的权限处理可以在vuex中进行。state数据中保存当前用户所有的路由对象,用于渲染左侧菜单;最重要的是,在actions中定义一个 筛选动态路由对象 的方法。

④ 在 路由导航守卫 的权限拦截处,拿到token令牌后调用actions方法,可以得到用户的 动态路由对象。然后用Vue.router提供的 router.addRoutes(路由规则对象数组) 方法,为router实例对象追加动态路由对象。

注意:用router.addroutes()方法后,要手动 next(to.path)。

(2)登出时重置路由权限(访问权限)

① 我们在登录时为router实例对象添加了动态路由,必须在退出登录时 重置,否则下一个用户登录后会继续使用上一个用户的权限。路由模块 提供了方法,只需要在 退出登录 时调用即可。

// 重置路由。新建一个路由实例,把新路由的路由规则对象(只有个静态路由)赋值给老路由实例。
export function resetRouter () {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

② 左侧菜单的渲染使用的是vuex中的路由数据,退出登录 时也要 重置

(3)功能权限

① 用户拥有了动态路由,就能访问对应的页面,但是页面中的某些按钮是否能点击等操作,受控于访问权限下的 功能权限。

②用 Vue.mixin( { }) ,给所有的vue组件 混入一个 methods方法,这个方法根据 功能点的权限标识 和用户信息里的 功能权限标识 进行比对,返回一个布尔值。

// 全局的混入对象

// 导入vuex
import store from '@/store'

export default {
  methods: {
    // 这里的参数key是系统某个功能的【权限标识】
    checkPermission (key) {
      // 这是vuex中保存的用户数据,里面有当前用户的【功能权限标识】
      //  store.state.user.userInfo.roles.points
      const { userInfo } = store.state.user
      // 如果用户有【功能权限标识】数组,并且有值,就进行筛选判断
      if (userInfo.roles.points && userInfo.roles.points) {
        return userInfo.roles.points.some(item => item === key)
      }
      return false// 如果连if都进不去,必定没有权限
    }
  }
}

③ 给组件中的按钮v-bind绑定这个方法,通过返回值判断当前用户是否可以使用这个按钮。

        <el-button
            size="small"
            type="primary"
            :disabled="!checkPermission('POINT-USER-ADD')"
          >新增员工</el-button>
9.路由传参

(1)编程式导航传参
① params形式 :参数不显示在地址栏

this.$router.push({name: "department",params:{userId:this.num})

② query形式:参数在地址栏内显示

this.$router.push({path:"/department",query:{name:"马冬梅",age:30})

③ 在组件内获取

this.$route.params.userId 或者 this.$route.query.name 进行获取

注意:跳转到 新开页 时,用params传递的参数是获取不到的。可以用 query传参;或者将params参数写到路由对象里。

(2)声明式导航传参

补充

① 有了前端路由,组件就定义在路由里面。最外面是一个根路由组件
② 为根路由组件 配置路由规则
③ 把根路由组件 挂载 到vue实例对象上。
④ 最后在vue实例对象控制的HTML结构中 添加路由占位符,渲染出整个根路由组件。

前端路由,就是通过 路由链接 生成一个 a标签,通过 路由组件 生成主体内容,然后用 路由规则 把这两项进行绑定。最后通过 路由占位符 指定渲染的位置。

  1. 在组件中,this.$router 获取到的是路由对象,可以调用路由的 push() 、go()、back()方法this.$route 获取到的是路由规则中的路径参数,可以获取到 path、query 等。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容