路由:一个路径对应一个组件
1.创建组件 例如: let home
2.配置路由映射表
3.注册路由映射表
4. 把路由挂载到根实例上;
基础路由
<div id="app">
<!-- to : 跳转的路由 tag:指定router-link渲染标签 -->
<!-- router-link:固定的,link用于点击 -->
<router-link to="/allhome" tag="button">首页</router-link>
<router-link to="/allperson" tag="button">个人中心</router-link>
<!-- 用于显示路由对应组件的地方 -->
<!-- 根据路由显示对应的组件 -->
<router-view></router-view>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
let home = {
data(){
return {
con:'首页'
}
},
created(){
// 显示组件时,需要再次创建组件实例;调用钩子函数;
console.log("组件创建");
},
beforeDestroy(){
console.log("销毁");
},
template:"<div>{{con}}</div>"
}
let person={
data(){
return {
con:'个人中心页'
}
},
template:"<div>{{con}}</div>"
}
// 配置路由映射表: 是路由和组件的配对情况
let routes =[{path:"/allhome",component:home},{path:"/allperson",component:person}];
// 注册映射表
let router = new VueRouter({
routes:routes//前面的属性名固定的不能变,属性值可以变
})
// 将路由挂载到根实例上
let vm = new Vue({
el:"#app",
data:{
},
router:router//前面的属性名固定的不能变,属性值可以变
})
</script>
2.vue-router中的方法
vue-router一定要放vue.js的后面
当切换组件时,组件会销毁;
当每一个被路由渲染出来的组件上有一个$router属性,在这个属性的原型上有一些操作路由的方法,37行this的原型链上
1.push : 直接跳转到当前路径对应的路由上 push(路径)
2.back : 回退到上一次的路由上
3.go(number):可以往前可以往后回退后前进几个
<div id="app">
<!-- to属性和路由映射表的path的属性值一样 -->
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/list"tag="button">列表页</router-link>
<!-- 展示路由对应的组件,当组件切换时,组件的DOM元素删除; -->
<router-view></router-view>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
let home={
data(){
return {
}
},
created(){
// 显示组件时,需要再次创建组件实例;调用钩子函数;
console.log("组件创建");
},
methods:{
goList(){
console.log(this);
//this.$router.push("/list")
}
},
beforeDestroy(){
console.log("销毁");
},
template:"<div>首页内容<button @click='goList'>去列表页</button></div>"
};
let list={
data(){
return {
}
},
methods:{
goback(){
console.log(this);
this.$router.go(-1);
}
},
template:"<div>列表页内容<button @click='goback'>返回</button></div>"
}
// 路由映射表
let routes = [{path:"/home",component:home},{path:"/list",component:list}];
// 注册路由映射表
let router = new VueRouter({
routes
});
// 挂载到根实例上
let vm = new Vue({
el:"#app",
router
});
</script>
3.路由的嵌套
- detail 和login都是list组件的子路由组件
- 在组件路由配置是,对象中有children属性,属性值是一个数组,里面配置了子路由,路由中不需要加父路由路径地址,同时也不需要加"/",当子路由进行匹配式,会自动加上父路由和/到子路由的前面;
- 二级路由不能直接配置到routes,应该找到它对应的以及路由,配置到其children属性上;
<div id="app">
<router-link to="/home" tag="button" class="a">首页</router-link>
<router-link to="/list" tag="button" class="b">列表页</router-link>
<router-view></router-view>
</div>
<template id="list">
<div>
列表页
<router-link to="/list/detail">详情页</router-link>
<router-link to="/list/login">登录页</router-link>
<router-view></router-view>
</div>
</template>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
let home={
template:"<div>首页</div>"
}
let list={
template:"#list"
};
let detail = {
template:"<div>详情页</div>"
}
let login = {
template:"<div>登录注册页</div>"
};
// detail 和login都是list组件的子路由组件
// 在组件路由配置是,对象中有children属性,属性值是一个数组,里面配置了子路由,路由中不需要加父路由路径地址,同时也不需要加"/",当子路由进行匹配式,会自动加上父路由和/到子路由的前面;
// 二级路由不能直接配置到routes,应该找到它对应的以及路由,配置到其children属性上;
let routes =[
{path:"/home",component:home},
{path:"/list",component:list,children:[
{path:"detail",component:detail},
{path:"login",component:login}
]}
];
let router = new VueRouter({
routes
})
let vm = new Vue({
el:"#app",
data:{
},
router
})
</script>
4.命名路由
<div id="app">
<!-- 将to改成动态属性 :to={name:组件的name名称} -->
<router-link :to="{name:'first'}">首页</router-link>
<router-view></router-view>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 通过名字取匹配路由
let home={
template:"<div>首页</div>"
}
let routes =[
{path:"/home",component:home,name:"first"}
];
let router = new VueRouter({
routes
})
let vm = new Vue({
el:"#app",
data:{
},
router
})
</script>
5.动态路由
动态路由:路由传参;路径后面是一个:变量;这就是动态路由,也可以叫路由动态传参;会把id以属性方式放到$route的params属性上,属性值就是路由实际的路径值
1.代码量少
2. 由于动态路由渲染的是同一个home组件,所以home组件不再销毁,当然也不再创建,复用了之前的组件,性能高;但是生命周期的钩子函数也不再执行;
<div id="app">
<router-link to="/home/1">第一本</router-link>
<router-link to="/home/2">第二本</router-link>
<router-link to="/home/3">第三本</router-link>
<router-view></router-view>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
// $router:push go back forward
let home={
// created(){
// //
// console.log(this.$route);
// },
// watch:{
// '$route'(to,from){
// console.log(to);// to: 要到达的组件的$route
// console.log(from);// from :上一个$route
// }
// },
// 路由守卫
// 在路由更新之前会默认调用该钩子函数
beforeRouteUpdate(to,from,next){
console.log(to);// 即将进入的目标路由的对象信息
console.log(from);// 即将离开路由的对象信息
console.log(next);// 函数
// 1. next 函数
// next(): 会立即进入到目标路由
// next(false):中断当前的导航;不再去访问下一个路由
if(to.params.id==3){
next({path:"/home/1"});
return;
}
// 权限校验
next();
},
template:"<div>这是我喜欢的第{{$route.params.id}}本书</div>"
}
let routes =[
{path:"/home/:id",component:home}
];
let router = new VueRouter({
routes
})
let vm = new Vue({
el:"#app",
data:{
},
router
})
</script>
6.路由传参
通过名字取匹配路由
1.:id 路由动态传参
2. query传参 这个用path传参
3. params传参 这个用name传参,通过冒号传的参都放在这个属性上了
<div id="app">
<router-link :to="{name:'first'}">首页</router-link>
<router-link :to="{name:'second'}">列表页</router-link>
<router-view></router-view>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
let home={
methods:{
goList(){
// push("/list")
// push({path:"",query:{}})
//this.$router.push({path:"/list",query:{id:100}})
this.$router.push({name:"second",params:{id:500}})
}
},
template:"<div>首页<button @click='goList'>去列表</button></div>"
}
let list={
created(){
//let id = this.$route.query.id;
console.log(this.$route.params.id);
},
template:"<div>列表页</div>"
}
let routes =[
{path:"/home",component:home,name:"first"},
{path:"/list",component:list,name:"second"}
];
let router = new VueRouter({
routes
})
let vm = new Vue({
el:"#app",
data:{
},
router
})
</script>
7.命名视图
<div id="app">
<!-- 将to改成动态属性 :to={name:组件的name名称} -->
<router-link :to="{name:'first'}">首页</router-link>
<!-- 没有name属性,会显示属性为default的组件 -->
<router-view></router-view>
<router-view name="b"></router-view>
<router-view name="c"></router-view>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
// 通过名字取匹配路由
let home={
template:"<div>首页</div>"
}
let foo = {
template:"<div>foo</div>"
}
let bar={
template:"<div>bar</div>"
}
let routes =[
{path:"/home",components:{//细节点,配置路由映射表的时候要加s,放对象
default:home,// home对应没有name属性的router-view,走默认
// 这个对象属性名和router-view的name属性值对应
b:foo,
c:bar
},name:"first"}
];
let router = new VueRouter({
routes
})
let vm = new Vue({
el:"#app",
data:{
},
router
})
</script>
7.路由的守卫
守卫: 7个
router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
全局守卫: beforeEach afterEach beforeResolve
路由独享守卫: beforeEnter 在路由配置上直接定义 beforeEnter 守卫
组件内部守卫: beforeRouteEnter beforeRouteUpdate beforeRouteLeave
<div id="app">
<router-link to="/home/1" tag="button">第一本</router-link>
<router-link to="/home/2" tag="button">第二本</router-link>
<router-link to="/home/3" tag="button">第三本</router-link>
<router-link to="/list" tag="button">列表</router-link>
<router-view></router-view>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
//切换到另一个组件,组件时会销毁的;
// 导航守卫:当切换导航时,会默认调用一些钩子函数,那么这些钩子函数就是导航的守卫;可以在进入这个导航或者离开这个导航时,在钩子函数中做一些事情
// 生命周期 11个
// 守卫: 7个
//router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
// 全局守卫: beforeEach afterEach beforeResolve
// 路由独享守卫: beforeEnter 在路由配置上直接定义 beforeEnter 守卫
// 组件内部守卫: beforeRouteEnter beforeRouteUpdate beforeRouteLeave
let home = {
beforeDestroy() {
//同样用的都是一个组件,例如home组件,这个函数不执行,也不销毁,切换到另一个组件,组件时会销毁的;例如list
// console.log(99)
},
beforeRouteEnter(to, from, next) {
// 这个钩子函数执行时进入组件实例之前,此时组件实例还没有创建;
console.log(this);// this==>window
console.log("home beforeRouteEnter")
next(vm => {
// 最后执行
// 当next执行传入回调函数,回调函数不能立即执行,等到组件实例创建好之后,才会触发这个回调函数;其中vm就是组件实例
//console.log(vm);
})
},
beforeRouteUpdate(to, from, next) {
//
console.log("home beforeRouteUpdate")
next()
},
beforeRouteLeave(to, from, next) {
// 当离开list这个组件时,会调用这个钩子函数
console.log(" home beforeRouteLeave")
next();
},
template: "<div>这是第{{$route.params.id}}本书</div>"
};
// 当第一次进入到list组件时,只触发了beforeRouteEnter;
let list = {
beforeRouteEnter(to, from, next) {
// 这个钩子函数执行时进入组件实例之前,此时组件实例还没有创建;
// console.log(this);// this==>window
console.log("list beforeRouteEnter")
next(vm => {
// 当next执行传入回调函数,回调函数不能立即执行,等到组件实例创建好之后,才会触发这个回调函数;其中vm就是组件实例
//console.log(vm);
})
},
// beforeRouteUpdate(to,from,next){
// 当复用这个组件并且更新了组件时,这个函数才会被调用;
// this--> 当前的组件实例
// //
// console.log("beforeRouteUpdate")
// next()
// },
beforeRouteLeave(to, from, next) {
// 当离开list这个组件时,会调用这个钩子函数
console.log(" list beforeRouteLeave")
next();
},
template: "<div>列表页内容</div>"
}
let routes = [{
path: "/home/:id", component: home, beforeEnter: (to, from, next) => {
console.log("home beforeEnter");
next();
}
}, {
path: "/list", component: list, beforeEnter: (to, from, next) => {//这些守卫与全局前置守卫的方法参数是一样的。
console.log("list beforeEnter");
next();
}
}]
let router = new VueRouter({
routes
});
// 全局的前置钩子函数;只要切换组件,就会执行
router.beforeEach((to, from, next) => {
// console.log(to);// 到哪去
// console.log(from);// 从哪来
console.log(1);
// 在这个钩子函数中获取到用户的信息,进行权限的校验,如果不符合要求,那么next不需要运行;或者直接跳转到首页或 403页面
next();// 只有执行了next,才会往下继续跳转路由;
});
router.beforeResolve((to, from, next) => {
// console.log(to);// 到哪去
// console.log(from);// 从哪来
console.log(2);
next();// 只有执行了next,才会往下继续跳转路由;
});
// 全局后置的钩子函数
router.afterEach((to, from) => {
// console.log(to);
console.log(3);
// 路由切换成功以后执行的钩子函数
});
console.log(router);
// 用户 /list 管理员 : /list /edit /home
// 相同路由切换路由时:路由守卫执行顺序beforeEach==>beforeEnter==>beforeRouteUpdate==>beforeResolve==>afterEach==>beforeResolve
//切换路由时执行顺序:beforeRouteLeave==>beforeEach==>beforeEnter==>beforeRouteEnter==>afterEach
//当进入组件时,先触发全局的前置钩子,然后触发进入组件的路由独享守卫,然后触发组件内部的beforeRouteEnter,最后触发全局的beforeResolve和全局后置钩子函数
let vm = new Vue({
el: "#app",
router
});
//导航被触发。
// 在失活的组件里调用离开守卫。
// 调用全局的 beforeEach 守卫。
// 在重用的组件里调用 beforeRouteUpdate 守卫(2.2 +) 。
// 在路由配置里调用 beforeEnter。
// 解析异步路由组件。
// 在被激活的组件里调用 beforeRouteEnter。
// 调用全局的 beforeResolve 守卫(2.5 +) 。
// 导航被确认。
// 调用全局的 afterEach 钩子。
// 触发 DOM 更新。
// 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
</script>
8.keep-alive
用于缓存组件,如果该组件还会再启用,那么可以使用keep-alive进行组件缓存和优化,提高性能,缓存的组件不需要销毁,也不需要再创建
<div id="app">
<button @click="fn">点一点</button>
<!-- // component : 内置组件,根据is属性来显示对应的组件;is属性的属性值保持和组件名字一致;然后可以显示对应的组件
// 如果是动态属性,那么会去data中取值 -->
<!-- <component is="second"></component> -->
<keep-alive>
<!-- keep-alive:用于缓存组件,如果该组件还会再启用,那么可以使用keep-alive进行组件缓存和优化,提高性能,缓存的组件不需要销毁,也不需要再创建 -->
<component v-bind:is="one"></component>
</keep-alive>
</div>
<script src="vue.js"></script>
<script src="../vue-router/dist/vue-router.js"></script>
<script>
// component 和keep-alive 都是内置组件,在VUE代码已经内置好的组件;
// 闭合标签使用组件
// component: 每次能动态显示一个组件,当切换下一个组件时,当前组件要销毁 把component放在keep-alive闭合标签中,就不销毁
// keep-alive : keep: 保持 alive:活力
// VUE项目的优化: keep-alive
let child={
data(){
return {
a:100
}
},
template:"<div>{{a}}</div>"
}
let first = {
destroyed(){
console.log("销毁")
},
components:{
child
},
// 生命周期的钩子函数
//9.activated 10.deactivated :这两个钩子函数呢一般配合<keep-alive><keep-alive/>来使用。
//11.errorCaptured
activated(){
// 当缓存组件有被显示出来时,会触发这个钩子函数
console.log(100);
},
deactivated(){
// 当缓存的组件隐藏时,会触发这个钩子函数;
console.log(200);
},
// 当子孙组件出错时,会调用这个钩子函数
errorCaptured(a,b,c){
console.log(a);
console.log(b);
console.log(c);
console.log("子组件报错")
},
template:"<div>我是老大<child></child></div>"
};
let second = {
template:"<div>我是老二</div>"
}
let third = {
template:"<div>我是老三</div>"
}
let vm = new Vue({
el:"#app",
data:{
one:"first"
},
methods:{
fn(){
let ary = ["first","second","third"];
let index = ary.indexOf(this.one);
if(index<2){
this.one = ary[index+1];
}else{
this.one = ary[0];
}
}
},
components:{
first,
second,
third
}
});
</script>