需求
- 完成插件的挂载
- 完成两个组件
- 实现监听与渲染
基本逻辑流程
- 始化时,将vue-router中配置的router配置项挂载到vue实例上
- 在页面中需要的位置添加router-link 与 router-view
- router-link 会改变url
- router-view 展示组件
- 添加路由监听,分为为url在load和change的时候触发
- 当路由发生变化时,router定义的响应式属性 current 会获取到当前的url地址,并根据地址去获取组件,最后在viwe中渲染组件
实现
- 组件router-view的实现
export default {
render(h) {
let component = null
this.$router.$options.routes.forEach(route => {
if (route.path === this.$router.current) {
component = route.component
}
})
return h(component)
}
}
- 组件router-link的实现
export default {
props: {
to: {
type: String,
required: true
}
},
render(h) {
return h('a', {
attrs: {
href: '#' + this.to
}
}, [
this.$slots.default
])
}
}
- my-router的实现
- 目标1:在全局挂载 router-link 和 router-view 两个组件
import Link from './my-router-link'
import View from './my-router-view'
VueRouter.install = function(_vue) {
vue = _vue
vue.component('router-link', Link)
vue.component('router-view', View)
}
export default VueRouter
- 目标2: 在实例创建的时候,将VueRouter创建的router配置挂载到vue根实例上
let vue
VueRouter.install = function(_vue) {
vue = _vue
vue.mixin({
beforeCreate() {
if (this.$options.router) {
vue.prototype.$router = this.$options.router
}
}
})
}
export default VueRouter
let vue
class VueRouter {
constructor(options) {
this.$options = options
const initial = window.location.hash.slice(1) || '/'
vue.util.defineReactive(this, 'current', initial)
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
}
onHashChange() {
this.current = window.location.hash.slice(1)
}
}
export default VueRouter
import Link from './my-router-link'
import View from './my-router-view'
let vue
class VueRouter {
constructor(options) {
this.$options = options
const initial = window.location.hash.slice(1) || '/'
vue.util.defineReactive(this, 'current', initial)
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
}
onHashChange() {
this.current = window.location.hash.slice(1)
}
}
VueRouter.install = function(_vue) {
vue = _vue
vue.mixin({
beforeCreate() {
if (this.$options.router) {
vue.prototype.$router = this.$options.router
}
}
})
vue.component('router-link', Link)
vue.component('router-view', View)
}
export default VueRouter
拓展、优化
- 提前做好组件映射,避免在url改变时重复执行循环遍历
class VueRouter {
constructor(options) {
this.routeMap = {}
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
});
}
}
export default {
render(h) {
const {routeMap, current} = this.$router
const component = routeMap[current] ? routeMap[current].component : null;
return h(component);
}
}
- 嵌套路由问题