- 背景:vue中如果想从一个页面到达另一个页面,可以使用路由来实现。
官方文档-vue-router
以下都是个人看文档和结合实际开发时用到的理解:
路由主要为我们实现以下功能: - 嵌套的路由/视图表:
如:
app.vue
<div id="app">
<router-view />
</div>
router/index.js
import Vue from 'vue';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home,
children: [{path: 'about', component: About}]
},
{
path: '/home',
name: 'Home',
component: Home,
children: [{path: 'about', component: About}]
}
];
const router = new VueRouter({
mode: 'history',
routes
});
export default router;
home.vue
<div class="home">
home
<router-view></router-view>
</div>
其中router-view是最顶层的出口(也就是最开始渲染的那一层),渲染最高级路由匹配到的组件,如app.vue中,在路由中设定了默认就是渲染了home.vue。同样地,一个被渲染组件同样可以包含自己的嵌套router-view, 也就是home.vue页面中也可以渲染自己的子路由,使用children属性来进行设置,其中嵌套了一个路由路径叫做about,渲染的组件为about.vue。
访问顶层出口(它的渲染组件为home.vue):
访问嵌套在home.vue中的路由:
有什么用?可以用来做点击选项卡切换不同的内容:
home.vue
<template>
<div class="home">
home
<router-link to="/home/login">登录</router-link>
<router-link to="/home/register">注册</router-link>
<router-view></router-view>
</div>
</template>
router/index.js:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import Login from '../views/login.vue';
import Register from '../views/register.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home,
children: [
{path: 'about', component: About},
{path: 'login', component: Login},
{path: 'register', component: Register}
]
},
{
path: '/home',
name: 'Home',
component: Home,
children: [
{path: 'about', component: About},
{path: 'login', component: Login},
{path: 'register', component: Register}
]
}
];
const router = new VueRouter({
mode: 'history',
routes
});
export default router;
如下图:
- 路由参数、查询、通配符: 平时我们会在url跳转(通常会使用Window Location进行跳转),跳转的时候自己拼接参数带过去,到达目标url又从链接上取(封装方法进行获取)下来,。而vue路由解放了我们双手——router的实例方法已经帮助我们封装好了这些方法。我们可以直接使用:
跳转链接,常用的有两种方式:
this.$router.push: 这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。类似location.href(path)
handleClick() {
this.$router.push('/userinfo');
console.log(window.history);
}
跳转的时候会有记录(没跳转之前我浏览器中一共有13条历史记录):
this.$router.replace: 它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录,类似于location.replace(path)
handleClick() {
this.$router.replace('/userinfo');
console.log(window.history);
}
跳转之后没有记录,浏览器不能回退到前一个页面(没跳转之前我浏览器中一共有13条历史记录):
添加参数:两种跳转方式添加参数方式类似
1.命名的路由:也就是参数通过vue的router实例去传递,参数不会在链接上显示出来。如果我们传递的数据太大了,直接拼接在url上,链接请求的过程就是get请求,参数是有内存限制的,数据太大的时候,可能会导致路由瘫痪。这时候可以通过命名的路由来实现。
handleClick() {
this.$router.push({name: 'userinfo', params: {userId: '123'}});
console.log(this.$router);
}
获取(在userinfo.vue中):
console.log(this.$route.params.userId);
如下图:
2.带查询参数:也就是我们发送的参数,都会在url上显示出来,这时候就是比较小的数据,相当于get请求
handleClick() {
this.$router.push({path: 'userinfo', query: {userId: '123'}});
console.log(this.$router);
}
获取(在userinfo.vue中):
console.log(this.$route.query.userId);
如下图:
注意: 两者除了在表现形式不一致外,还有一个区别:
在使用 命名的路由 传递参数,跳转过去后刷新页面,params会丢失,而query不会。这时候我们也可以通过缓存的方式进行存储解决这个问题。
扩展问题:如果我们传递的参数数据太庞大,超过了query允许的范围,又不想用缓存来处理params刷新丢失的问题,那么如何解决?个人建议:庞大的数据需要不同页面传递,,或许是后端接口设计得不合理,可以考虑协商调整接口,使用查询参数传递关键信息过来,然后在目标页面进行接口请求。
前端的工作,不仅仅是为了把数据展示上去就好,如果接口设计得不合理,会导致本来简单的事情在前端页面处理起来很繁杂,在开发过程中,如果项目业务逻辑复杂,拆分组件的时候,会根据前端的知识进行组件化拆分,建议也要结合接口进行验证拆分得是否合理(bug也会降低很多),不然就会更复杂化流程。
- 基于 Vue.js 过渡系统的视图过渡效果:vue提供了 以下标签,可以用来进行过度:
<router-link to="/home/login">登录</router-link>
<router-link to="/home/register">注册</router-link>
<div @click="handleClick">
个人中心
</div>
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
写css的类名也是有规则的,官方文档给出这样的解释:
其中v就是我们定义的属性name的属性值
过渡模式:由于transition 的的默认行为 - 进入和离开同时发生, 同时生效的进入和离开的过渡不能满足所有要求,也就是过渡起来很不自然,所以 Vue 提供了过渡模式
in-out:新元素先进行过渡,完成之后当前元素过渡离开。
out-in:当前元素先进行过渡,完成之后新元素过渡进入。
上面的代码,当我们点击登录或者注册的时候,路由切换会时内容更换相对平缓,有一个无到有的动画效果。
也可以看看 官方transitions
上面的动画样式是自己定义的,也可以结合第三方动画库Animate.css来实现。
- 细粒度的导航控制:
全局守卫:有前置和后置守卫,可以理解为监督路由变更的哨兵:
beforeEach: 前置守卫, 进入路由之前,使用场景:如果一个页面需要登录才能进去,我们可以在此进行拦截,当前用户没有登录,就拦截转到登录页面。
to: 目标路由
from: 要离开的路由
next: 进行管道中的下一个钩子,使用了全局守卫,一定要确保这个也执行了, 否则会中断跳转。
const router = new VueRouter({
mode: 'history',
routes:[]
});
router.beforeEach((to, from, next) => {
console.log(to, from);
next();
});
如从 到达 home到userinfo
router.afterEach: 全局后置守卫,到达目标路由后
router.afterEach((to, from) => {
// ...
})
上述两个守卫是全局的,对所有的路由都生效,同样我们可以设置单个路由独享的守卫,路由独享守卫,只有这一个:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
},
}
]
})
有了全局守卫和路由独享守卫外,还有组件内的守卫
<template>
<div class="home">
home
<router-link to="/home/login">登录</router-link>
<router-link to="/home/register" exact>注册</router-link>
<div @click="handleClick">
个人中心
</div>
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {
msg: 'hello'
};
},
components: {
},
// 路由进入前
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
// console.log(this.msg); //=>TypeError
console.log('beforeRouteEnter');
next();
},
// 路由更新前
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
this.msg = 'world';
console.log('beforeRouteUpdate:', this.msg);
next();
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
console.log(to, from, 'beforeRouteLeave:', this.msg); //=>hello
next();
},
methods: {
handleClick() {
}
}
};
</script>
如下图:
初次进入当前路由(调用beforeRouteEnter):
路由更新:这里指的是子路由改变(beforeRouteUpdate):
离开当前路由:
跳转到userinfo路由(调用了beforeRouteLeave):
官方给的导航解析流程:
理解:
1.假设/home是从/other这个路由过来的,当在浏览器中打开的时候,就会触发导航(1),/other这个组件会失活,它会调用组件守卫beforeRouteLeave(2),接着调用全局守卫beforeEach(3),进到/home前会先调用独享路由beforeEnter(5),有异步路由也调用(6),当home.vue组件被激活 时候调用 组件守卫beforeRouteEnter(7)、(8),接着导航被确认跳来了/home(9),再调用全局守卫afterEach,接着就触发DOM更新(11),然后触发next(12)
2. 如果从/home跳去它的嵌套子路由/home/login,就会重用home.vue,才会调用组件守卫beforeRouteUpdate(4)
如下图,初次进入home会触发以下守卫:
点击登录,会重用home,组件守卫只会调用一个beforeRouteUpdate,全局守卫都会调用了:
点击去到个人中心:会调用所有的全局守卫,home组件的beforeRouteLeave,以及userinfo组件的beforeRouteEnter
-
HTML5 历史模式或 hash 模式,在 IE9 中自动降级:vue-router默认的模式为hash模式,它一共有两种模式:
1.hash
2.history
设置方式:在创建路由实例的时候:const router = new VueRouter({ mode: 'history', //默认值为hash routes:[] });
区别:
两者最明显的区别就在于表现形式上:
hash会有#:
history没有#:
区别二:
hash模式:如果输入的路由不存在,页面同样也会自动跳到首页。
history模式:如果输入的路由,不存在,页面就会404,这时候前端可以进行设置通用路由覆盖所有:
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
这样,找不到对应路由的配置的时候,就都会进入这个页面,就不会404了,当然也可以让后端进行配置这些。
下面的这三个先不写了,可以去官网看
- 模块化的、基于组件的路由配置: 路由元信息
- 自定义的滚动条行为: scrollBehavior
- 带有自动激活的 CSS class 的链接