最近一直在react搭建博客,把vue忘的快差不多了
所以复习一下vue的路由部分
我是用vue脚手架的时候勾选了路由配置,所以自动下载了路由的包,如果没有勾选,需要执行下载命令
npm install vue-router
一般新启一个框架项目,都会把路由配置独立出来
创建一个router的文件夹,在文件夹内新建一个index.js文件,在里面进行路由的统一配置
//引入vue和vue-router
import Vue from "vue";
import Router from "vue-router";
//在vue中使用包要用Vue.use()方法
//使用router
Vue.use(Router);
//配置各种路由的地方
const routes = [];
//一些路由的默认配置
const router = new Router({
mode: "history",//还有hash模式
base: process.env.BASE_URL,
routes
});
export default router;
vue的路由有两种模式,一种是history,一种是hash。两者在使用方法上并没有区别。
但是有一点其他区别:
- hash模式url上永远带着#号,history模式不带。有的app上不允许url里带#号,这时候就不得不用history模式
- 在访问二级页面的时候,做回车刷新操作,会丢失页面,需要和后端人配合重新定向到我们的首页路由上
定义最简单的路由。每个路由应该映射一个组件。
- "component" 对应一个组件
- "name"'是路由的名字,在组件中链接路由时可以通过name的形式
//引入vue组件
import Home from "../views/Home.vue";
import My from "../views/My.vue";
const routes = [
{ path: "/", component: Home, name: "home" },
{ path: "/my", component: My, name: "my" }
];
在需要跳转的地方使用路由 ,这里有编程式/声明式两种方式跳转
<template>
<div id="app">
<ul>
<li @click="go('/')">首页</li>
<router-link to='/my'>我的</router-link>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {
methods: {
go(path) {
this.$router.push(path);
}
}
};
</script>
这样配置过可以在浏览器中使用看看,会发现一个问题,连着点击导航的时候浏览器会有下面的报错:
Navigating to current location (****) is not allowed
这是因为用编程式跳转时候,点击两次push方法会在路由中添加相同的路由,可以在router的统一配置文件中添加一段代码解决
Vue.use(Router);
const routerPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(error => error);
};
定义带儿子的路由(嵌套路由)。在需要跳转的地方使用路由时是和简单路由一样的,子路由生成的路径是'/my/one',跳转时候要注意路径的正确性,不然会发生奇怪的事情😊
import My from "../views/My.vue";
import MyOne from "../views/son/MyOne.vue";
import MyTwo from "../views/son/MyTwo.vue";
const routes = [
{
path: "/my",
component: My,
name: "my",
children: [
{path: "one",component: MyOne},
{path: "two",component: MyTwo}
]
}
];
定义动态传参的路由。接收参数有两种方式
第一种,直接用$route获取
//模拟一个组件,接收传来的参数
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const routes = [
{ path: "/user/:id", component: User, },
]
第二种,整合到props中,涉及到命名视图后面讲解
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router =[
{ path: '/user/:id', component: User, props: true },
// 对于包含命名视图的路由,须分别为每个命名视图添加 props
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
传参的几种方式
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<router-link :to="{ path: 'user', query: { userId: 123 }}">User</router-link>
router.push({ path: `/user/${userId}` })
router.push({ name: 'user', params: { userId: 123 }})
router.push({ path: 'user', query: { userId: 123 }})
重定向的三种方式
//从a重定向到b
const routes = [{ path: '/a', redirect: '/b' }]
const routes = [{ path: '/a', redirect: { name: 'b' }}]
const routes = [
{ path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
路由别名
const routes = [{ path: '/a', component: A, alias: '/b' }]
什么是导航守卫?
路由跳转是一个大过程,细分为跳转前、跳转后、跳转中等等等,在这些过程中的一些钩子函数就是导航守卫
to 是即将进入的目标路由对象
from 是正要离开的路由
next()继续向下执行/next(false)终止执行/next({path:'/', query:{ id:1 }})跳转指定路由并传参
//全局前置守卫 改变所有路由
router.beforeEach((to, from, next) => {
//路由跳转前执行 通常用来做登录判断
next(false) //所有路由不会跳转
})
//全局解析守卫 改变所有路由
router.beforeResolve((to, from, next) => {
//路由跳转前执行
next(false) //所有路由不会跳转,但是会执行组件内的路由守卫和异步路由组件
});
//全局后置钩子 不会改变路由状态
router.afterEach((to, from) => {
//路由跳转时执行
//没有回调函数
});
//写在路由配置中的单个路由独有的守卫 只会改变当前路由
beforeEnter: (to, from, next) => {
//当前路由跳转前执行
next(false) //当前配置的路由不会跳转
},
//写在组件内部的三个组件内的路由守卫
beforeRouteEnter(to, from, next) {
//当前组件渲染前执行 不能调用 this
next(vm => {
// 通过 `vm` 访问当前组件的VueComponent
})
}
beforeRouteUpdate(to, from, next) {
//组件被复用时调用时执行 如动态传参的相同路由相互跳转
}
beforeRouteLeave(to, from, next) {
//组件离开时执行 通常用来禁止用户在还未保存修改前突然离开
//next(false) 路由不会跳转
}
路由元信息的用处是什么?
在刚才的导航守卫中有一个叫beforeEach的钩子,一般会用来做登录校验。如果我们有20个路由其中10个需要做登录校验,那么要写10个if条件是不是很麻烦,路由元信息就可以解决这个麻烦的问题。
路由元信息就是给路由增加一个meta对象,在对象中可以设置一些自定义的状态
const routes = [
{ path: "/", component: Home, meta: { isLogin: true }}
];
router.beforeEach((to, from, next) => {
//遍历$route. matched中的meta字段,为true的禁止跳转
if (
to.matched.some(function(item) {
return item.meta.isLogin;
})
) {
next(false);
} else {
next();
}
});
路由过度动画。直接搬官网的源码了
<transition name=''>
<router-view></router-view>
</transition>
//基于路由配置
<transition :name="transitionName">
<router-view></router-view>
</transition>
// 接着在父组件内 watch $route 决定使用哪种过渡
watch: {
'$route' (to, from) {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
}
路由懒加载的三种方式。
第一种,使用resolve
异步机制,用require
代替import。
const routes = [
{
path: '/',
name: 'user',
component: resolve => require(['@/components/user'], resolve)
}
]
第二种,通过Promise
的resolve
机制。
const routes = [
{
path: '/',
name: 'user',
component: () => import('@/components/user.vue')
}
]
第三种,通过webpack提供的require.ensure(),可以通过参数中的webpack
将js分开打包。
const routes = [
{
path: '/',
name: 'user',
component: resolve => require.ensure([], () =>
resolve(require('@/components/user')), 'webpack'
)
}
]