知识点1:
transition和router-view可以结合使用。因为router-view满足transition的条件。
<!-- App.vue文件 -->
<template>
<div id="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<h1>Routing</h1>
<hr>
<router-view name="header-top"></router-view>
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</div>
</template>
<script>
import Herder from './components/header'
export default {
components: {
'app-header': Herder,
}
}
</script>
<style>
.fade-enter{
opacity: 0;
}
.fade-enter-to{
opacity: 1;
}
.fade-enter-active{
transition: opacity 1s;
}
.fade-leave{
opacity: 1;
}
.fade-leave-to{
opacity: 0;
}
.fade-leave-active{
transition: opacity 1s;
}
</style>
![00c7aa14338f322a85dbc9d3a5ae2f7a.gif](https://img-blog.csdnimg.cn/img_convert/00c7aa14338f322a85dbc9d3a5ae2f7a.gif)
知识点2:
锚点
需求: 在编辑页面上写一个button按钮(锚点),让别人定位到这里。
如果是在单页面,写一个a标签,href中写锚点id即可,或者在浏览器中写锚点id也行。
<template>
<div>
<p>请在此处编辑...</p>
<p>{{ $route.query.a }}</p>
<p>{{ $route.query.a }}</p>
<a href="#btn">去锚点</a>
<div style="height: 1000px"></div>
<button class="btn btn-primart" id="btn">锚点</button>
</div>
</template>
<style scoped>
p {
color: #0c8918;
}
</style>
![254ef763ce9c755c0c38888e4f1f50b2.gif](https://img-blog.csdnimg.cn/img_convert/254ef763ce9c755c0c38888e4f1f50b2.gif)
如果是在用户详情页面中跳转的时候锚点,该怎么做?
在路由配置中写一个滚动行为scrollBehavior。
scrollBehavior有三个参数: to from savePostion,return一个包含x和y的坐标或者选择器selector,如果定义在路由配置中,则全局中组件切换都会触发该函数。
to: 到哪里去
from: 从哪里来
savePostion: 记录浏览器滚动条上次的位置,使用浏览器前进后退按钮有效
import Vue from 'vue'
import Router from 'vue-router'
import Home from './components/home'
import User from './components/user'
import userStart from './components/user/userStart'
import userDetail from './components/user/userDetail'
import userEdit from './components/user/userEdit'
import Header from './components/header'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
components: {
default: Home, // 匹配到'/' 没有命名使用这个
'header-top': Header, // 匹配到'/' 使用该命名的使用这个
},
name: 'home',
},
{
path: '/user',
component: User,
children: [{
path: "",
component: userStart,
},{
path: ":id",
component: userDetail,
},{
path: ":id/edit",
component: userEdit,
name: "userEdit"
}]
},{
path: "*",
redirect: "/user" // 重定向
}
],
scrollBehavior(to, from, savePostion) {
console.log(to)
console.log(from)
return {
// x: 0,
// y:200,
selector: "#btn"
}
}
// 这个行为配置在全局,全局中只要有组件切换都会触发
})
![6fa79ae1be3ef644e71a3ce6a63b63e9.gif](https://img-blog.csdnimg.cn/img_convert/6fa79ae1be3ef644e71a3ce6a63b63e9.gif)
缺点: 任意两个路由跳转都会跳到这里(有滚动条的时候)。
解决: 写点逻辑,只有to页面才能锚点
scrollBehavior(to, from, savePostion) {
// console.log(to)
// console.log(from)
console.log(savePostion)
if(to.hash){
return {
selector: "#btn"
}
}
}
savePostion示范:
![44374ea3f107c7f56fa4755688c53d63.gif](https://img-blog.csdnimg.cn/img_convert/44374ea3f107c7f56fa4755688c53d63.gif)
知识点3:
3个进入之前的守卫,2个走之前的守卫
进入之前守卫
- 全局守卫: 获取vue实例,使用beforEach方法
beforEach: 在每一次进入路由之前都会执行该函数(拦截器),有to, from, next三个形参。
to和from不说了,next方法调用才会执行跳转。
![290121b6a71ac457623a598d9025e949.png](https://img-blog.csdnimg.cn/img_convert/290121b6a71ac457623a598d9025e949.png)
![a1ccfb6b5d15429195adbef898e96a87.gif](https://img-blog.csdnimg.cn/img_convert/a1ccfb6b5d15429195adbef898e96a87.gif)
![eb3b5b89a3c87a698ad8cc393043fffa.gif](https://img-blog.csdnimg.cn/img_convert/eb3b5b89a3c87a698ad8cc393043fffa.gif)
next的三种情况
next(false): 跟无next一样
next(): 真实跳转
next("/user"): 可以重定向,适合用户验证失效。可以写成对象: path、query等
2. 局部守卫
beforeEnter
![66ff475cd2f567de1fffad0294493e0b.png](https://img-blog.csdnimg.cn/img_convert/66ff475cd2f567de1fffad0294493e0b.png)
![203bd5f3641eb2d75506cde9e6c17eb3.gif](https://img-blog.csdnimg.cn/img_convert/203bd5f3641eb2d75506cde9e6c17eb3.gif)
3. 组件守卫
beforeRouteEnter
![635a2e4e9ebb7e5d48f6d414c7c98dd7.png](https://img-blog.csdnimg.cn/img_convert/635a2e4e9ebb7e5d48f6d414c7c98dd7.png)
![9ca25335667cd62d7025a5b0fb7bc55f.gif](https://img-blog.csdnimg.cn/img_convert/9ca25335667cd62d7025a5b0fb7bc55f.gif)
如果要使用这种方法改变数据,请使用vm来做vue实例的this。然后通过回调函数执行。
![9ef23838aaf3042592043e6b9f8df365.png](https://img-blog.csdnimg.cn/img_convert/9ef23838aaf3042592043e6b9f8df365.png)
![31e7ddd349857cf0b18bc26b91c08b77.gif](https://img-blog.csdnimg.cn/img_convert/31e7ddd349857cf0b18bc26b91c08b77.gif)
走之前守卫
- beforeLeave
没有next走不出去。
![60b3e5881a489d7f2d033e882483f149.png](https://img-blog.csdnimg.cn/img_convert/60b3e5881a489d7f2d033e882483f149.png)
![842d0d6a46ae9acd8854ceba73b81b4d.gif](https://img-blog.csdnimg.cn/img_convert/842d0d6a46ae9acd8854ceba73b81b4d.gif)
<template>
<div>
<p>请在此处编辑...</p>
<p>{{ $route.query.a }}</p>
<p>{{ $route.query.a }}</p>
<button class="btn btn-primary" @click="confirm=true">保存</button>
<div style="height: 1000px"></div>
<button class="btn btn-primary" id="btn">锚点</button>
</div>
</template>
<script>
export default {
data() {
return {
confirm: false,
}
},
beforeRouteEnter(to, from, next) {
console.log("组件守卫")
console.log(this)
next(vm => {
console.log(vm)
})
},
beforeRouteLeave(to, from, next) {
if(this.confirm){
next()
}else{
if(confirm("提示: 你的数据未保存,直接离开将丢失")) {
next()
}else{
next(false)
}
}
}
}
</script>
<style scoped>
p {
color: #0c8918;
}
</style>
![f54583b7b036697a848c2dcd084e3cd8.gif](https://img-blog.csdnimg.cn/img_convert/f54583b7b036697a848c2dcd084e3cd8.gif)
知识点4: (小项目不需要)
软加载
由于webpack把所有js文件打包到了一起,如果遇上大型项目,加载将会变慢,我们把所有的路由打包成不同的js文件。
代码分离思想:不使用import,写成函数,在切换组件的时候才执行。
import Vue from 'vue'
import Router from 'vue-router'
import Home from './components/home'
const User = () => import('./components/user')
const userStart = () => import('./components/user/userStart')
const userDetail = () => import('./components/user/userDetail')
const userEdit = () => import('./components/user/userEdit')
const Header = () => import('./components/header')
// import User from './components/user'
// import userStart from './components/user/userStart'
// import userDetail from './components/user/userDetail'
// import userEdit from './components/user/userEdit'
// import Header from './components/header'
Vue.use(Router)
const router = new Router({
mode: 'history',
routes: [
{
path: '/',
components: {
default: Home, // 匹配到'/' 没有命名使用这个
'header-top': Header, // 匹配到'/' 使用该命名的使用这个
},
name: 'home',
},
{
path: '/user',
component: User,
children: [{
path: "",
component: userStart,
},{
path: ":id",
component: userDetail,
beforeEnter(to, from, next) {
console.log("局部路由")
next()
}
},{
path: ":id/edit",
component: userEdit,
name: "userEdit"
}]
},{
path: "*",
redirect: "/user" // 重定向
}
],
scrollBehavior(to, from, savePostion) {
// console.log(to)
// console.log(from)
// console.log(savePostion)
if(to.hash){
return {
selector: "#btn"
}
}
}
// 这个行为配置在全局,全局中只要有组件切换都会触发
})
router.beforeEach((to, from, next) => {
next()
})
export {router}
// 在main.js中也需要用命名方式引入
![3648765f327a2a23f9cf51e2297d8d44.gif](https://img-blog.csdnimg.cn/img_convert/3648765f327a2a23f9cf51e2297d8d44.gif)
为什么一开始就加载了1.js,2.js,3.js文件,因为开启了预加载功能。
![df90b44d3ad643e4e948c920c6055fe1.png](https://img-blog.csdnimg.cn/img_convert/df90b44d3ad643e4e948c920c6055fe1.png)