实现vue-router需要用到vue的基本概念
- 插件
- 混入
- Vue.observable()
- 插槽
- render函数
- 运行时和完整版的vue
路由模式
- hash模式原理
把url中#后面的内容作为路径地址,我们可以直接通过location.url来切换浏览器中的地址
如果改变了#后面的内容,那么浏览器不会向服务端请求这个地址,但是他会把这个地址记录到浏览器的访问历史中
当hash改变以后我们需要记录hash的变化并做相应的处理。当hash发生变化以后会触发hashchange事件,我们需要在 hashchange的事件中我们只需要记录当前的地址,并找根据当前的地址找到对应的组件进行渲染。 - history模式原理 通过调用history.pushState()方法来改变地址栏,pushState方法仅仅是改变当前浏览器的地址栏,并且把的地址 记录到浏览器的访问历史,并不会真正的向服务器发送请求,通过监听popstate事件,可以监听浏览器历史的变化, 在popstate事件的处理函数中,可以记录浏览器的改变地址,要注意的是当调用pushstate或者replaceState的时候 并不会触发该事件。当点击浏览器的前进、后退按钮或者调用go和back方法的时候才会触发该事件,最后当地址改变以后要根据当前的地址找到对应的组件进行渲染。
手动实现history模式下的vue-router
实现vuerouer 插件需要定义的方法和数据有
- options
- routerMap
- data
- constructor(options)
- install
- init
- initEvent
- createRouterMap
- initComponents
let _Vue = null
export default class VueRouter ({
static install (vue){
// 1 判断插件是否安装
if(this.install.installed){
return
}
this.install.installed = true
// 2 把vue构造函数记录到全局变量中
_Vue = vue
// 3 把创建vue实例时候传入的router对象注入到vue实例上去
_Vue.mixin({
beforeCreate () {
if(this.$options.router){
_Vue.prototype.$router = this.$options.router
}
}
})
}
constructor (options) {
this.options = options
this.routerMap = {}
this.data = _Vue.observable({
current:location.pathname
}) //把data变成响应式的
}
init () {
this.careteRouterMap()
this.initComponents(_Vue)
}
createRouterMap () {
this.options.router.forEach(router=>{
this.routerMap[router.path] = router.component
})
}
//注意如果注册组件你想使用template模板
//需要使用完整版vue vue-cli创建的vue默认不包含编译器
//开启完成版vue 在vue.comfig.js 文件里面 配置runtimeCompiler:true
initComponents (Vue) {
const self = this
Vue.component('router-link',{
props:{
tp:String
}
render (h) {
return h ('a',{
attrs:{
href:this.to
},
on:{
click:this.clickHander
}
}
,[this.$solts.default])
},
methods:{
clickHander (e) {
history.pushState({},'',this.to)
this.$router.data.current = this.to
e.preventDefault()
}
}
})
Vue.component('router-view',{
render(h){
const component = self.routerMap[self.data.current]?self.routerMap[self.data.current]:self.routerMap['*']
return h(component)
}
})
}
initEvent () {
window.addEventListener('popstate',()=>{
this.data.current = window.loaction.pathname
})
}
})