Vue Router
yuhuo2022-06-22开发库框架库
HTML 配置
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- <router-link> 将转化为带正确 href 属性的 <a> 标签-->
<!-- 等同于 router.push() -->
<router-link :to="{path: '/home', query: {a: 1}}">Go to Home</router-link>
<!-- 等同于 router.replace() -->
<router-link to="/about" replace>Go to About</router-link>
</p>
<!-- 渲染顶层路由匹配的组件 -->
<router-view></router-view>
<!-- 添加过渡 -->
<router-view v-slot="{ Component, route }">
<!-- 可以通过meta动态指定过渡名称 -->
<transition :name="route.meta.transition || 'fade'" >
<!-- 使用key强制过渡,避免组件被复用时忽略过渡 -->
<component :is="Component" :key="route.path"/>
</transition>
</router-view>
</div>
<!-- About -->
<template id="component_about">
<div class="about">
<h1>About</h1>
<!-- 渲染嵌套路由匹配的组件 -->
<router-view name="Header"></router-view>
<router-view></router-view>
</div>
</template>
路由配置
// router.js
import VueRouter from "vue-router";
import Home from "./Home.js";
import About from "./About.js";
const router = VueRouter.createRouter({
// hash 模式
history: VueRouter.createWebHashHistory(),
routes: [
{
// 静态路径
path: "/about",
// 动态路径:携带路径参数
path: "/about/:mode/user_:userId",
// 参数后加括号,设定正则表达式
path: "/about/user_:userId(\\d+)_search"
// 参数后面加量词 * + ? 设为可重复
// $route.params.chapters 将是个数组
path: '/about/:chapters+'
// 正则表达式 + 可重复
path: "/about/:chapters(.*)*"
// 静态导入组件
component: About,
// 路径参数转成 props
props: true,
// 静态 props
props: {
width: 100
},
// 动态 props
props: route => { return { query: route.query.q }},
// 名称
name: "About",
// 元信息
meta: {
title: "关于"
},
// 路径是否区分大小写,默认 false
sensitive: false,
// 路径是否区分带尾部斜线,默认 false
strict: false,
// 嵌套路由(以父路由路径为 /about 示例)
children: [
{
// 绝对路径
path: '/about_child',
// 相对路径,相对于父路由路径,
path: 'child', // 匹配 /about/child
path: '', // 匹配 /about
// 多别名
alias: [
// 绝对路径
"/topic",
// 相对路径,相对于父路由路径,匹配 /about/info
"info"
],
// 单别名,别名中需要包含相同路径参数
alias: "/topic/:mode/u_:userId",
// 命名视图
components: {
// 动态导入组件
default: () => import("./Main.js"),
Header: () => import("./Header.js"),
},
// 每个命名视图定义 props
props: {
default: true,
Header: false
}
},
],
},
// 注意:导航守卫不会应用在被重定向路由上
{
path: "/page/home",
// 重定向可以省略 component,除非有 children
component: Home,
// 绝对路径
redirect: '/page/about',
// 相对路径,相对当前路径,匹配 /page/about
redirect: 'about',
// 名称
redirect: { name: 'About' },
// 方法
redirect: to => {
return { path: '/page/about', query: { q: to.params.text } }
},
},
],
// 全局sensitive
sensitive: false,
// 全局strict
strict: false,
// 滚动行为
scrollBehavior (to, from, savedPosition) {
// 页面滚动位置
return {
top: 0,
left: 0,
};
// 指定元素的相对偏移量
return {
el: '#main',
top: -10,
left: 0,
// 滚动方式:auto 立即到达(默认),smooth 滑动到达
behavior: 'smooth',
};
// 按下后退/前进按钮时有效
if (savedPosition) {
// 浏览器的原生表现
return savedPosition;
}
// 延迟滚动
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ left: 0, top: 0 });
}, 500)
});
}
});
export default router;
// main.js
import router from "./router.js";
import App from "./App.js";
const app = Vue.createApp(App);
app.use(router);
app.mount("#app");
路由对象
$route
// About.js
export default {
template: "#component_about",
// 路径参数转成 props
props: ["mode", "userId"],
created() {
// 路由路径 /about/:mode/user_:userId
// 访问路径 index.html#/about/pc/user_1001?a=1&b=2
this.$route = {
fullPath: "/about/pc/user_1001",
hash: "",
href: "#/about/pc/user_1001",
// router.js中匹配的路由对象
matched: [{}],
meta: { title: "关于" },
name: "About",
params: { mode: "pc", userId: "1001" },
path: "/about/pc/user_1001",
query: { a: "1", b: "2" },
redirectedFrom: undefined,
};
},
// 当 从 /about/pc/user_1001 导航到 /about/pc/user_1002 时,
// 仅路径参数变化,相同的组件实例将被重复使用,生命周期钩子不会被调用,
// 可以通过监听 $route.params 变化,或者添加导航守卫,以做出响应
watch:{
"$route.params": (toParams, fromParams) => {
// 路径参数变化
}
},
}
$router
// About.js
import router from "./router.js";
export default {
template: "#component_about",
create() {
// 两者是同一对象,使用this的方式可以减少导入
this.$router == router;
},
// 路由路径:/about/:mode/user_:userId
methods: {
// 跳转路由
push() {
// 路径
this.$router.push('"/about/pc/user_1001?a=1&b=2"').then((result) => {
if(result) {
// 导航被阻止,result 为错误对象
} else {
// 导航成功,result 为 undefined
}
});
// 路径 + 查询参数(注意:路径参数在此无效)
this.$router.push({
path: '/about/pc/user_1001',
// 查询参数,可选
query: { a: 1, b: 2 },
// 是否替换,等同于 $router.replace(),默认false
replace: true,
});
// 名称 + 路径参数 + 查询参数
this.$router.push({
name: 'About',
// 路径参数
params: {
mode: "h5", // 必传
userId: "1003", // 必传
sex: "男" // 可选,跳转后刷新页面就不存在了
},
// 查询参数,可选
query: { a: 1, b: 2 },
});
},
// 替换路由
replace() {
// 参数同 push
this.$router.replace({...});
},
// 解析路由
resolve() {
// 返回 route 对象,参数同 push
this.$router.resolve({...});
},
// 移动路由
go() {
// 向前移动x条记录,x可为负数
this.$router.go(1);
// 等同 router.go(1);
this.$router.forward();
// 等同 router.go(-1);
this.$router.back();
},
// 动态路由
dynamic() {
// 添加路由
// 如果新增加的路由与当前位置相匹配,
// 需要执行 router.push() 或 router.replace() 才显示新路由
const removeRoute = router.addRoute({ path: '/about', name: 'about' component: About });
// 将嵌套路由添加到现有路由中
router.addRoute('about', { path: 'child', component: Child })
// 名字相同时,重设路由
router.addRoute({ path: '/other', name: 'about', component: Other });
// 删除路由,所有的别名和子路由也会被同时删除
// 根据添加路由的返回方法删除
removeRoute();
// 根据路由名称删除
router.removeRoute('about');
// 检查路由是否存在
router.hasRoute('about');
// 获取一个包含所有路由记录的数组
router.getRoutes();
}
},
};
导航守卫
全局守卫
const router = VueRouter.createRouter({ ... });
// 前置守卫
router.beforeEach((to, from) => {
// 重定向,参数同 router.push()
return { name: 'Login' };
// 取消导航
return false
// 无返回,或者返回 true,则正常执行
});
// 解析守卫
router.beforeResolve((to, from) => {
// 重定向,参数同 router.push()
return { name: 'Login' };
// 取消导航
return false
// 无返回,或者返回 true,则正常执行
})
// 后置守卫
router.afterEach((to, from) => {
// 不会改变导航本身,可以做一下辅助工作,如更改页面标题
})
路由守卫
function handle1(to, from) { }
function handle2(to, from) { }
const routes = [
{
path: "/about",
component: About,
// 只在进入不同路由时触发,params、query 或 hash 改变时不会触发
beforeEnter: (to, from) => {
// 重定向,参数同 router.push()
return { name: 'Login' };
// 取消导航
return false
// 无返回,或者返回 true,则正常执行
},
// 函数数组
beforeEnter: [ handle1, handle2 ],
},
];
组件守卫
export default {
// 导航确认前被调用,组件实例还未创建,不能访问 this
beforeRouteEnter(to, from, next) {
// 导航被确认的时候执行回调,通过 vm 访问组件实例
next(vm => {});
},
// 在当前路由改变,但是该组件被复用时调用,如仅路径参数变化时
beforeRouteUpdate(to, from) {
},
// 在导航离开该组件的对应路由时调用
beforeRouteLeave(to, from) {
},
}
导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫(2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫(2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。