参照vue-router的使用方法
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
使用
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
分析
vue.use() //说明 vue-router 插件中有install 方法
使用时候 有 routerLink 和routerView组件,routerLink组件根据传入to
属性指定不同链接,引入不同的组件,将组件渲染再routerView所在的位置。
根据hash地址的变化渲染不同的组件。
实现
步骤.调用install方法的时候,如果是根组件包含router信息,
1.进行初始化routerLink,routerView两个组件,
2.设置路由path和组件的映射关系routerMap,
3.监听路由的变化事件。
初始化组件:
routerLink接受一个props和一个slot转换成A标签
routerView组件根据path的变化,从routerMap中取相应的组件信息,进行渲染(需要是响应式的)将对应的组件渲染再router–view的区域。
初始化sourceMap:
根据实例初始化时的routes参数,转化为path和component的映射关系
初始化事件:
事件监听,监听hashchange和load事件更改当前的路径(hash模式)。
路由守卫 :
hashchange时候根据e(事件对象),获取 from,to,执行next()时候进行改变hash
实例方法:
全局push方法: 在install将就$router 挂载全局,push时候 改变当前路径。
代码实现
let Vue // 为什么不import?
export default class Svuerouter {
constructor(options) {
this.$options = options;
this.routerMap={}
//Vue.observable方法将数据设置为响应式,让render函数动态的渲染(new Vue也可以,vue.util.defineReactive方法也可以,$set()应该也可以)
//方法一
// _vue.util.defineReactive(
// this,"current","/about"
// )
this.vm = Vue.observable({
current:location.hash.slice(1)||'/'
})
}
static install(_vue, option) {
Vue = _vue;
//全局混入生命周期,让插件初始化的时候获取到路由的相关参数
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
this.$options.router.init();
Vue.prototype.$router = this.$options.router
}
},
})
}
init() {
this.initcomponents()
this.initrouter()
this.initevent()
}
initcomponents() {
//初始化router-link组件,为什么不用template?可以使用jsx,建议使用render函数(注意当前this的指向)
Vue.component("router-link", {
props: {
to: {
type: String,
require: true
}
},
render(h) {
// return <a href={`#${this.to}`}>{this.$slots.default}</a>
return h("a", {
attrs: {
href: `#${this.to}`
}
}, [this.$slots.default])
}
});
// 渲染对应的路由组件(注意当前this的指向)
Vue.component("router-view",{
render:(h)=>{
let component = this.routerMap[this.vm.current].component||null
return h(component)
}
})
}
//初始化组件path和组件对象的映射关系
initrouter() {
this.$options.routes.forEach((item)=>{
this.routerMap[item.path]=item
})
}
initevent() {
window.addEventListener("hashchange",this.getcurrent.bind(this))
window.addEventListener("onload",this.getcurrent.bind(this))
}
getrouterLife(e){
let from,to;
if(e.type == "hashchange"){
from = e.oldURL.split("#")[1];
to = e.newURL.split("#")[1];
}else{
from = '';
to = location.hash.slice(1);
}
return {
from,
to
}
}
//判断是否有路由守卫
getcurrent(e){
if(this.routerMap[this.vm.current].beforeRouterEnter){
let {from,to} = this.getrouterLife(e)
this.routerMap[this.vm.current].beforeRouterEnter(from,to,()=>{
this.vm.current = location.hash.slice(1);
})
}else{
this.vm.current = location.hash.slice(1);
}
}
//添加Vuerouter实例的方法
push(path){
this.vm.current = path
}
}