路由

路由是键值对,key 对应不同 url 路径,value 对应相应组件。以实现 SPA 不同页面的切换。

vue-router 是什么

vue 的一个插件库,专门用来实现 SPA 应用。

SPA 是什么

单页 Web 应用(single page web application)。 整个应用只有一个完整的页面,点击页面中的导航链接不会刷新页面,只会做页面的局部更新。数据通过 ajax 请求获取。

路由的使用

  • router.js
//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: "/about",
      component: About,
    },
    {
      path: "/home",
      component: Home,
    },
  ],
});
  • main.js
Vue.use(VueRouter);

//创建vm
new Vue({
  el: "#app",
  render: (h) => h(App),
  router: router,
});
  • App.vue
<!-- Vue中借助router-link标签实现路由的切换 -->
<router-link to="/about">About</router-link>
<router-link to="/home">Home</router-link>

<!-- 指定组件的呈现位置 -->
<router-view></router-view>

路由的注意点

  • 路由切换意味着前端组件的切换,处于非活跃的组件是被销毁等待之后重建。
  • 每个组件拥有自己的$route 属性,保存自己的路由信息
  • 整个应用只有一个$router 属性

router-link最后会转成<a>标签

路由的历史记录采用栈结构存储,默认采用 push 模式;给<router-link>设置 replace 属性表示路由记录采用替换模式。

多级路由

  • router.js
//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: "/about",
      component: About,
    },
    {
      path: "/home",
      component: Home,
      //   子路由不用加 /
      children: [
        {
          path: "news",
          component: News,
        },
        {
          path: "message",
          component: Message,
        },
      ],
    },
  ],
});
  • Home.vue
<router-link to="/home/news">News</router-link>
<router-link to="/home/message">Message</router-link>
<router-view></router-view>

命名路由

使用 name 属性简化路由路径 🌻

  • router.js
{
    path: "message",
    component: Message,
    children: [
        {
            name: "routeName",
            path: "detail",
            component: Detail,
        },
    ],
},
  • Message.vue
<router-link :to="{ name: 'routeName' }"></router-link>

路由传参

$route.query

通过 $route.query 对象传递参数。

  • router.js
export default new VueRouter({
  routes: [
    {
      path: "/home",
      component: Home,
      children: [
        {
          path: "news",
          component: News,
        },
        {
          path: "message",
          component: Message,
          children: [
            {
              path: "detail",
              component: Detail,
            },
          ],
        },
      ],
    },
  ],
});
  • Detail.vue
<template>
  <ul>
    <li>消息编号:{{ $route.query.id }}</li>
    <li>消息标题:{{ $route.query.title }}</li>
  </ul>
</template>
  • Home.vue
<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul>
        <li>
          <router-link to="/home/news">News</router-link>
        </li>
        <li>
          <router-link to="/home/message">Message</router-link>
        </li>
      </ul>
      <router-view></router-view>
    </div>
  </div>
</template>
  • Message.vue
<template>
  <div>
    <ul>
      <li v-for="m in messageList" :key="m.id">
        <!-- 跳转路由并携带query参数,to的字符串写法 -->
        <!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>; -->

        <!-- 跳转路由并携带query参数,to的对象写法 -->
        <router-link
          :to="{
            path: '/home/message/detail',
            query: {
              id: m.id,
              title: m.title,
            },
          }"
        >
          {{ m.title }}
        </router-link>
      </li>
    </ul>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    };
  },
};
</script>

$route.params

通过 $route.params 对象传递参数。

配置路由 path 属性的时候需要使用占位符声明接收参数

path:'detail/:id/:title',

特别注意

此时 router-link 使用 to 的对象写法,不能使用 path 配置项,必须使用 name 属性配置

props

路由配置可以接收 props 选项,目的就是为了让路由组件更方便的收到参数。

  • router.js
{
	path:'detail',
	component:Detail,
    // props:{a:1,b:'hello'}
    // props:true
    props($route){
        return {
            id:$route.query.id,
            title:$route.query.title,
        }
    }
}
  1. props 的第一种写法,值为对象,该对象中的所有 key-value 都会以 props 的形式传给 Detail 组件
  2. props 的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有 params 参数,以 props 的形式传给 Detail 组件。局限在于不能接收 query 参数
  3. props 的第三种写法,值为函数,vue-router 会传入$route 参数,可以使用解构赋值的形式精简代码

函数式路由

不借助 <router-link> 实现路由跳转,让路由跳转更加灵活。

利用 VueRouter 对象实例的方法,Vue 项目里一般通过 this.$router 访问。

  • this.$router.push(options: object)
  • this.$router.replace(options: object)
  • this.$router.back()
  • this.$router.forward()
  • this.$router.go(n: number)

缓存路由组件

  • 缓存单个路由
<keep-alive include="News">
    <router-view></router-view>
</keep-alive>
  • 缓存多个路由组件
<keep-alive :include="['News', 'Message']">
    <router-view></router-view>
</keep-alive>
  • 缓存所有路由组件
<keep-alive>
    <router-view></router-view>
</keep-alive>

生命周期钩子

  • activated,VueRouter 对象独有,组件激活时调用
  • deactivated,VueRouter 对象独有,组件失活时调用

路由守卫

路由守卫既对路由进行权限控制。

全局守卫

在路由配置文件里设置 meta 元属性即可 ✍️

  • router.js
{
  name:'zhuye',
  path:'/home',
  component:Home,
  meta:{title:'主页'},
  children:[
    {
      name:'xinwen',
      path:'news',
      component:News,
      meta:{isAuth:true,title:'新闻'}
    },
  ]
}
  1. 全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to, from, next) => {
  if (to.meta.isAuth) {
    //判断是否需要鉴权
    if (localStorage.getItem("school") === "xxx") {
      next();
    } else {
      alert("学校名不对,无权限查看!");
    }
  } else {
    next();
  }
});
  1. 全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to, from) => {
  document.title = to.meta.title || "zhang13press";
});

独享守卫

很多时候,需要给某个特殊组件设置路由权限,可在 router.js 路由配置文件内给该组件单独配置 beforeEnter 属性

{
  name:'xinwen',
  path:'news',
  component:News,
  meta:{isAuth:true,title:'新闻'},
  beforeEnter: (to, from, next) => {
    if (to.meta.isAuth) {
      //判断是否需要鉴权
      if (localStorage.getItem("school") === "xxx") {
        next();
      } else {
        alert("学校名不对,无权限查看!");
      }
    } else {
      next();
    }
  };
}

组件内守卫

在对应组件内设置路由规则,而不是在路由配置文件。

  • xxx.vue
export default {
  //通过路由规则,进入该组件时被调用
  beforeRouteEnter(to, from, next) {
    if (to.meta.isAuth) {
      //判断是否需要鉴权
      if (localStorage.getItem("school") === "xxx") {
        next();
      } else {
        alert("学校名不对,无权限查看!");
      }
    } else {
      next();
    }
  },

  //通过路由规则,离开该组件时被调用
  beforeRouteLeave(to, from, next) {
    next();
  },
};

路由模式

  • hash,默认模式,url 中#后的内容就是 hash 值,它不会包含在 HTTP 请求中,既不会带给服务器
  • history,在路由配置文件添加mode:'history'开启,node.js 一般采用connect-history-api-fallback中间件解决携带前端路径造成的 404 问题

小结

  • beforeEach
  • afterEach
  • beforeEnter
  • beforeRouteEnter
  • beforeRouteLeave