Vue Router

捕获路由

匹配参数

1
2
3
4
//匹配所有参数
{ path: "*" }
//匹配`/user-`开头的任意路径
{ path: "/user-" }

含有通配符的路由通常放在最后,{path:"*"}通常用于 404 页面.

路由后缀

当使用通配符时,$route.params内会自动添加一个名为pathMatch.包含了 URL 通过通配符被匹配的部分:

1
2
3
//给出一个路由 { path: "/user-*"}
this.$router.push("/user-admin");
this.$route.params.pathMatch; //'admin'

路由跳转

router.push

声明式: <router-link :to="...">
编程式: router.push(...)

1
2
3
4
5
6
7
8
//字符串
router.push("home");
//对象
router.push({ path: "home" });
//命名的路由
router.push({ name: "user", params: { userId: "123" } });
//带查询参数,变成/register?plan=private
router.push({ path: "register", query: { plan: "parivate" } });

注意nameparams搭配,pathquery搭配

1
2
3
4
5
const userId = '123'
router.push({name:"user", params:{ userId }) //=> /user/123
router.push({path: `/user/${userId}`}) //=> /user/123
//这里的params不生效
router.push({ path: 'user', params: { userId }}) //=>/user

router.replace

此方法和 router.push 很像,不同的是不会向 history 添加新记录,而是替换掉当前的 history 记录.
声明式: <router-link :to="..." replace>
编程式: router.push(...)

router.go

此方法参数是整数,类似window.history.go()

和 window 的方法类似

router.push => window.history.pushState
router.replace => window.history.replaceState
router.go => window.history.go

路由命名

通过name给路由命名

1
2
3
4
5
//跳转调用
<router-link :to="{name: 'user',params: { userId: 123 } }>User</router-link>
//编程式写法
router.push({name: 'user', params: {userId:123}})

重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const router = new VueRouter({
routes: [
{path: '/a', redirect: '/b' }
]
})
//重定向到命名路由
const router = new VueRouter({
routes: [
{path: '/a', redirect: { name: 'foo'} }
]
})
//方法
const router = new VueRouter({
routes: [
{path: '/a', redirect: to => {
//方法接收 目标路由作为参数
//return 重定向的 字符串路径/路径对象
}
]
})

别名

区别:
重定向: 用户访问/a,URL 被替换为/b,匹配路由为 /b
别名: /a的别名是/b.用户访问/b时,URL 会保持为/b,但是路由匹配是/a.就像访问了/a一样.

1
2
3
const router = new VueRouter({
routes: [{ path: "/a", component: A, alias: "/b" }],
});

路由传参

通过在路由 routes 中设置 props 进行解耦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const User = {
props: ["id"],
template: "<div>User {{ id }}</div>",
};
const router = new VueRouter({
routes: [
{ path: "/user/:id", component: User, props: true },

// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: "/user/:id",
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false },
},
],
});

如果 props 为 true,就可以通过组件获取参数.

history 模式

除了在 new Router()中设置mode: history外,还需要后端设置.

路由钩子(导航守卫,路由守卫)

beforeEach

可以设置进度条,
重置 store

1
2
store.commit("SET_TABS", []);
store.dispatch("app/goToTop", true);

判断是否有不需要登录就可以看的页面
如果需要跳转到登录
如果已登录,操作一些需要做的

1
2
3
4
5
//未登录不能验证身份
router.beforeEach((to, from, next) => {
if (to.name !== "Login" && !isAuthenticated) next({ name: "Login" });
else next();
});

路由独享守卫

在路由配置上的beforeEnter守卫:

1
2
3
4
5
6
7
8
9
10
11
const router = new VueRouter({
routes: [
{
path: "/foo",
component: Foo,
beforeEnter: (to, from, next) => {
//...
},
},
],
});

路由元信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const router = new VueRouter({
routes: [
{
path: "/foo",
component: Foo,
children: [
{
path: "bar",
component: Bar,
// a meta field
meta: { requiresAuth: true },
},
],
},
],
});

一个路由匹配到的所有路由记录会暴露为$route对象(还有在导航守卫中的路由对象)的$route.matched数组.因此,我们需要遍历$route.matched来检查路由记录中的meta字段.

如果有的页面不用登录就可以访问,就可以在 meta 中设置字段.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!auth.loggedIn()) {
next({
path: "/login",
query: { redirect: to.fullPath },
});
} else {
next();
}
} else {
next(); //确保一定要调用 next()
}
});

路由守卫

分为三种,全局,单个路由独享,组件的.

全局

相当于程序的页面生命周期.
全局守卫 3 个,beforeEach, beforeResolve, afterEach
分别表示进入路由前,解析前,离开路由时.
beforeEach: 路由跳转前触发,参数to,form,next,主要用于登录验证.
beforeResolve: 和 beforeEach 类似,在 beforeEach 和 beforeRouteEnter 之后,afterEach 之前.
afterEach: 在路由跳转后触发.参数to,from.

next()函数的作用是回调验证导航.
next(): 什么都不传,表示继续执行.多个 next()则可能不会解析或报错.
next(false): 中断当前导航.
next(‘/‘): 跳转到该地址.
next(error): 钩子中止将错误传递给 router.onerror()回调.

1
2
const router = new VueRouter();
router.beforeEach((to, from, next) => {});

路由独享守卫

beforeEnter: 只在进入路由时触发.不会在params,query,hash改变时触发.

1
2
3
4
5
6
7
8
9
const router = new VueRouter({
routes: [
{
path: "./foo",
component: Foo,
beforeEnter: (to, from, next) => {},
},
],
});

组件内守卫

有三个,beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave.
分别代表,渲染该组件对应的路由被验证前调用,路由复用同一个组件,离开当前路由

1
2
3
4
5
6
7
8
9
const Foo = {
template: "...",
beforeRouteEnter(to, from) {},
beforeRouteUpdate(to, from) {
// 比如动态参数/users/:id/,在user/1和user/2之间切换,那就复用同一个组件,
// 就会被调用,而且可以使用this,其他两个不行,因为组件没有了
},
beforeRouteLeave(to, from) {},
};

滚动行为

切换到新路由时,滚动到顶部或者保持原来的位置,可以设置滚动行为.

此功能只在支持history.pushState的浏览器可用

1
2
3
4
5
6
const router = new VueRouter({
routes: [...],
scrollBehavior(to, from, savedPosition) {
return {x:0, y: 0}
}
})

scrollBehavior方法接收tofrom路由对象.第三个参数savedPosition当且仅当popstate导航(浏览器的前进后退按钮触发)时才可用.

1
2
3
4
5
6
7
scrollBehavior(to, form, savedPosition){
if(savedPosition) {
return savedPosition
}else{
return {x:0,y:0}
}
}

滚动到锚点

1
2
3
4
5
scrollBehavior(to, form, savedPosition){
if(to.hash) {
return to.hash
}
}

平滑滚动

1
2
3
4
5
6
7
scrollBehavior(to, form, savedPosition){
if(to.hash) {
return {
selector: to.hash,
behavior: 'smooth'
}
}

路由懒加载

1
2
3
4
5
6
{
path: '/bbsHome',
name: 'BbsHome',
component: () => import(/* webpackChunkName: "portal" */ '@/views/bbs/bbsHome.vue'),
meta: { title: '论坛首页', auth: 'no' }
},

常见问题

  1. 两个页面参数不同使用同一组件,默认情况下当这两个页面切换时并不会触发 created 或者 mounted 钩子。
  • 通过watch$route 的变化处理
1
2
3
4
5
6
7
watch: {
$route() {
if($route) {
...
}
}
}
  • 通过在<route-view>上加唯一的key保证渲染.
1
<router-view :key='$route.fullPath'></router-view>

刷新当前页面

1
2
3
4
this.$router.go(0);
location.reload();
//这个只刷数据
this.$forceUpdate;

跳转到其他页面

1
2
3
4
//直接跳转,可以用后退返回
window.location.href = url;
//打开新的窗口
window.open(url);