路由:一个路径对应一个组件
1.创建组件
2.配置路由映射表
3.注册路由映射表
4. 把路由挂载到根实例上;
<body>
<div id="app">
<!-- to : 跳转的路由 tag:指定router-link渲染标签 -->
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. tag:指令router-link渲染成啥标签-->
<!-- <router-link> 默认会被渲染成一个 `` 标签 -->
<router-link to="/allhome" tag="button">首页</router-link>
<router-link to="/allperson" tag="button">个人中心</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>
// 路由:一个路径对应一个组件
// 1.创建组件
// 2.配置路由映射表
// 3.注册路由映射表
// 4. 把路由挂载到根实例上;
let home = {
data() {
return {
con: '首页'
}
},
template: "{{con}}"
}
let person = {
data() {
return {
con: '个人中心页'
}
},
template: "{{con}}"
}
// 配置路由映射表: 是路由和组件的配对情况
let routes = [{
path: "/allhome",
component: home
}, {
path: "/allperson",
component: person
}];
// 注册路由映射表
let router = new VueRouter({
routes: routes // routes 属性名不可以改
})
// 将路由挂载到根实例上
let vm = new Vue({
el: "#app",
data: {
},
components: {
home,
person
},
router
})
</script>
</body>
引入时:vue-router一定要放vue.js的后面
当切换组件时,组件会销毁;
当每一个被路由渲染出来的组件上有一个$router属性,在这个属性的原型上有一些操作路由的方法
1.push : 直接跳转到当前路径对应的路由上 push(路径)
2.back : 回退到上一次的路由上
3.go(number):可以往前可以往后回退后前进几个
原生:
window.history
window.history.go(-1)
<body>
<div id="app">
<!-- to属性 -->
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/list" tag="button">列表页</router-link>
<!-- 展示对应的组件,当组件切换时,组件的DOM元素删除 -->
<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>
//window.history
//window.history.go(-1)
// vue-router一定要放vue.js的后面
// 当切换组件时,组件会销毁;
// 当每一个被路由渲染出来的组件上有一个$router属性,在这个属性的原型上有一些操作路由的方法
// 1.push : 直接跳转到当前路径对应的路由上 push(路径)
// 2.back : 回退到上一次的路由上
// 3.go(number):可以往前可以往后回退后前进几个
let home = {
data() {
return {}
},
created() {
// 显示组件时,需要再次创建组件实例;调用钩子函数
console.log("创建首页");
},
methods: {
goList() {
console.log(this);
this.$router.push("/list")
}
},
template: "首页内容",
beforeDestroy() {
console.log("销毁首页");
},
};
let list = {
data() {
return {}
},
methods: {
goBack() {
console.log(this);
// this.$router.back("/home")
this.$router.go(-1)
}
},
template: "列表页"
};
// 路由映射表
let routes = [{
path: "/home",
component: home
}, {
path: "/list",
component: list
}];
// 注册路由映射表
let router = new VueRouter({
routes
});
// 挂载到根实例上
let vm = new Vue({
el: "#app",
router
});
</script>
</body>
在组件路由配置是,对象中有children属性,属性值是一个数组,里面配置了子路由,子路由中不需要加父路由路径地址,同时也不需要加"/",当子路由进行匹配式,会自动加上父路由和/到子路由的前面;
子路由path后面也可以从一级路由到耳机路由
二级路由不能直接配置到routes,应该找到它对应的以及路由,配置到其children属性上;
下面例子:detail 和login都是list组件的子路由组件
<body>
<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="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script>
let home={
template:"首页"
}
let list={
template:"#list"
};
let detail = {
template:"详情页"
}
let login = {
template:"登录注册页"
};
// 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>
</body>
将to改成动态属性 :to={name:组件的name名称}
通过名字取匹配路由
<body>
<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:"首页"
}
let routes =[
{path:"/home",component:home,name:"first"}
];
let router = new VueRouter({
routes
})
let vm = new Vue({
el:"#app",
data:{
},
router
})
</script>
</body>
动态路由:路由传参;路径后面是一个 :变量 这就是动态路由,也可以叫路由动态传参;会把id以属性方式放到$route的params属性上,属性值就是路由实际的路径值
1.代码量少
2. 由于动态路由渲染的是同一个home组件,所以home组件不再销毁,当然也不再创建,复用了之前的组件,性能高;但是生命周期的前四个钩子函数也不再执行;
<body>
<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="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script>
// $router:push go back forward
// $route:
// 路由的动态传参:
// 路由传参有哪些方式;
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: "这是我喜欢的第{{$route.params.id}}本书"
}
// 动态路由:路由传参;路径后面是一个:变量;这就是动态路由,也可以叫路由动态传参;
会把id以属性方式放到$route的params属性上,属性值就是路由实际的路径值
// 1.代码量少
// 2. 由于动态路由渲染的是同一个home组件,所以home组件不再销毁,当然也不再创建,
复用了之前的组件,性能高;但是生命周期的钩子函数也不再执行;
let routes = [{
path: "/home/:id",
component: home
}];
let router = new VueRouter({
routes
})
let vm = new Vue({
el: "#app",
data: {},
router
})
</script>
</body>
- id 动态路由传参;路径后面是一个:变量;这就是动态路由,也可以叫路由动态传参;会把id以属性方式放到$route的params属性上,属性值就是路由实际的路径值
- query传参 path
- params传参 name 命名路由
<body>
<div id="app">
<router-link :to="{name:'first'}">首页</router-link>
<router-link :to="{name:'second'}">列表页</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>
// 通过名字取匹配路由
// 1. id 动态路由传参;路径后面是一个:变量;这就是动态路由,也可以叫路由动态传参;
会把id以属性方式放到$route的params属性上,属性值就是路由实际的路径值
// 2.query传参 path
// 3.params传参 name
let home = {
methods: {
goList() {
// this.$router.push({
// path: "/list",
// query: {
// id: 100
// }
// }),
this.$router.push({
name: "second",
params: {
id: 500
}
})
}
},
template: "首页 "
}
let list = {
created() {
// console.log(this.$route)
// let id = this.$route.query.id;
// console.log(id);
console.log(this.$route);
let id = this.$route.params.id;
console.log(id);
},
template: "列表页"
}
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>
</body>
没有name属性,会显示属性为default的组件
let routes =[
{path:"/home",components:{
default:home,// home对应没有name属性的router-view
// 这个对象属性名和router-view的name属性值对应
b:foo,
c:bar
},name:“first”}
];
<body>
<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="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script>
let home={
template:"首页"
}
let foo = {
template:"foo"
}
let bar={
template:"bar"
}
let routes =[
{path:"/home",components:{
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>
</body>
redirect: 重定向
- routes:[{path:"/a",redirect:"/home"}]
- routes:[{path:"/a",redirect:{name:“路由名字”}}]
<body>
<div id="app">
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/list" tag="button">列表页</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>
// 路由{path:"",component:"",children:[{path:"",component:""},
{path:"",component:""}]}
let home = {
template: "首页内容"
};
let list = {
template: "列表页内容"
};
let found = {
template: "页面404"
};
// redirect: 重定向
// 1. routes:[{path:"/a",redirect:"/home"}]
// 2. routes:[{path:"/a",redirect:{name:"路由名字"}}]
let routes = [{
path: "/",
// component: home
// 一个地址一个组件,如果想用就重定向,
}, {
path: "/home",
component: home
}, {
path: "/list",
component: list
}, {
path: "/a",
component: found
}, {
path: "*",
redirect: "/home"
}];
let router = new VueRouter({
routes
});
let vm = new Vue({
el: "#app",
router
})
</script>
</body>
导航守卫:当切换导航时,会默认调用一些钩子函数,那么这些钩子函数就是导航的守卫;可以在进入这个导航或者离开这个导航时,在钩子函数中做一些事情
守卫: 7个
全局守卫: beforeEach afterEach beforeResolve
路由独享守卫: beforeEnter
组件内部守卫: beforeRouteEnter beforeRouteUpdate beforeRouteLeave
<body>
<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>
<!-- IMPORT JS -->
<script src="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script>
//切换到另一个组件,组件时会销毁的;
// 导航守卫:当切换导航时,会默认调用一些钩子函数,那么这些钩子函数就是导航的守卫;
可以在进入这个导航或者离开这个导航时,在钩子函数中做一些事情
// 生命周期 11个
// 守卫: 7个
// 全局守卫: beforeEach afterEach beforeResolve
// 路由独享守卫: beforeEnter
// 组件内部守卫: beforeRouteEnter beforeRouteUpdate beforeRouteLeave
let home = {
beforeDestroy() {
// console.log("销毁");
},
template: "这是第{{$route.params.id}}本",
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();
}
};
// 当第一次进入到list组件时,只触发了beforeRouteEnter
let list = {
template: "列表内容",
// 组件内的守卫
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("组件内的守卫-list-beforeRouteUpdate");
// next()
// },
beforeRouteLeave(to, from, next) {
// 当离开list这个组件时,会调用这个钩子函数
console.log("组件内的守卫-list-beforeRouteLeave");
next();
}
};
let routes = [{
path: "/home/:id",
component: home,
beforeEnter: (to, from, next) => {
// 路由独享的守卫
console.log("home-路由独享的守卫");
next()
}
}, {
path: "/list",
component: list,
beforeEnter: (to, from, next) => {
// 路由独享的守卫
console.log("list-路由独享的守卫");
next()
}
}];
let router = new VueRouter({
routes
})
// 全局的前置钩子函数;只要切换组件,就会执行
router.beforeEach((t0, form, next) => {
console.log("beforeEach-全局前置的钩子函数");
// console.log(to);// 到哪去
// console.log(from);// 从哪来
// console.log(1);
// 在这个钩子函数中获取到用户的信息,进行权限的校验,如果不符合要求,
那么next不需要运行;或者直接跳转到首页或 403页面
next(); // 只有执行了next,才会往下继续跳转路由;
})
// 全局解析守卫
router.beforeResolve((t0, form, next) => {
console.log("beforeResolve-全局解析守卫");
// console.log(to);// 到哪去
// console.log(from);// 从哪来
// console.log(2);
next(); // 只有执行了next,才会往下继续跳转路由;
})
// 全局后置的钩子函数
router.afterEach((t0, form) => {
// 路由切换成功以后执行的钩子函数
console.log("afterEach-全局后置的钩子函数");
// console.log(to);
// console.log(3);
})
// 用户 /list 管理员 : /list /edit /home
// 切换路由时:路由守卫执行顺序beforeEach==>beforeEnter==>beforeRouteUpdate==>
beforeResolve==>afterEach
//当进入组件时,先触发全局的前置钩子,然后触发进入组件的路由独享守卫,
然后触发组件内部的beforeRouteEnter,最后触发全局的beforeResolve和全局后置钩子函数
let vm = new Vue({
el: '#app',
router
});
// 从第三本到列表
// 组件内的守卫-home-beforeRouteLeave beforeEach-全局前置的钩子函数
list-路由独享的守卫 组件内的守卫-list-beforeRouteEnter beforeResolve-全局解析守卫
afterEach-全局后置的钩子函数 调用beforeRouteEnter守卫中传给next的回调函数
// 从列表到第三本
// 组件内的守卫-list-beforeRouteLeave beforeEach-全局前置的钩子函数
home-路由独享的守卫 组件内的守卫-home-beforeRouteEnter beforeResolve-全局解析守卫
afterEach-全局后置的钩子函数 调用beforeRouteEnter守卫中传给next的回调函数
// 从第三本到第二本
// beforeEach-全局前置的钩子函数 组件内的守卫-list-beforeUpdata
beforeResolve-全局解析守卫 afterEach-全局后置的钩子函数
</script>
</body>
class VueRouter{
constructor(options){
const {routes}=options;
// 监听当前页面的hash值的切换
// 当第一次解析页面时,会有一个默认的hash值
/// 循环遍历routes,把path和component重新放入一个新的对象中
// {"/home/:id":home}
this.routeMap = routes.reduce((prev,next)=>{
prev[next.path]=next.component;
return prev;
},{});
//
// this ==> VueRouter的实例,也是每一个组件上的_router
Vue.util.defineReactive(this.route={},'path',"/");
window.addEventListener("load",()=>{
// 如果没有hash值,那么给其赋默认值/;如果本来就有hash,什么也不做;
location.hash?null:location.hash="/";
})
window.addEventListener("hashchange",()=>{
// 当页面hash值发生改变以后,会触发这个方法;1.a标签 2.手动
// 获取当当前页面的hash值,获取到#后面的字符串;
let path = location.hash.slice(1);
this.route.path = path;
})
}
}
//在Vuex注入了$store,在路由注入_router
VueRouter.install=function(_Vue){
_Vue.mixin({
// 给每一个组件新增一个_router的属性,这个属性的属性值是VueRouter的实例
beforeCreate(){
// this==> 每一个组件实例
if(this.$options&&this.$options.router){
// 给每一个组件实例新增_router属性,属性值就是VueRouter的实例;
这是给Vm这个Vue实例新增
this._router=this.$options.router;
}else{
// 给vm的组件的实例新增
this._router=this.$parent && this.$parent._router;
}
// 给每一个实例添加$route属性,
Object.defineProperty(this,"$route",{
value:{
route:this._router.route// ? 这个route
}
});
// 注册两个内置组件
// router-link router-view
// 注册全局组件
<router-link to="/home"></router-link>
let child = {}
Vue.component("router-link",{
props:{
to:String
},
// template:"",
render(createElement){// h是一个createdElement,这个方法可以直接接受一个组件;
createElement 用来创建虚拟的DOM
//return createElement("a",{},首页)
// render : 渲染函数
// render: 将虚拟DOM可以转成真实的DOM;这个函数返回什么,
那么最终router-link就渲染成什么
// this==> 当前的组件实例
// return + 组件;可以把组件渲染成一个真实的DOM;
// return h(child);
// return
// $slots
return <a href={`#${this.to}`}>this.$slots.default</a>
}
});
// router-view : 根据页面的hash值显示对应的组件
Vue.component("router-view",{
render(createdElement){
// 这个传递一个动态的组件名字
return createElement(this._router.routeMap[this._router.route.path])
}
})
}
})
};
let router=new VueRouter({
routes:[]
})
let vm = new Vue({
router,
render(){
}
})
export default VueRouter;