需求分析
- 作为一个插件存在:实现VueRouter类和install方法。
- 实现两个全局组件:router-view用于显示匹配组件内容,router-link用于跳转。
- 监控url变化:监听hashchange或popstate事件。
- 响应最新url:创建一个响应式的属性current, 当它改变时获取对应组件并显示。
一、编写一个MVueRouter插件
在vue2中使用vue-router需要单独安装引入,使用方式如下
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './route/index'
Vue.use(VueRouter)
// 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes
})
// 创建和挂载根实例。
// 通过 router 配置参数注入路由,从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
安装后需要通过Vue.use()注册,这说明可以把vue-router作为一个插件。
mvue-router.js
// 实现一个插件:挂载$router
class MVueRouter {
install(_vue) {
let Vue = _vue
// 挂载$router
// 怎么获取根实例中获取router选项
// 利用全局或如,在beforCreate钩子里面获取选项
Vue.mixin({
// router只有在根实例中存在
beforeCreate () {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
}
}
export default MVueRouter
二、实现两个全局组件
这一步要实现两个全局的组件,<mvue-link></mvue-link>用于路由的跳转,<mvue-view></mvue-view>用于动态的的替换展示路由地址对应的组件。
mrouter-link.js
// router-link 组件实质上就是一个a标签,可以触发路由change事件
export default {
props: {
// to 属性: 跳转的url
to: {
type: String,
require: true
}
},
render(h) {
// 渲染结果: <a href="/path">aaa</a>
// 渲染函数三个参数: 标签名称、属性集合、子元素数组
return h('a', { attrs: { href: `#${this.to}` } }, [this.$slots.default])
// JSX语法
// return <a href={'#' + this.to}>{this.$slot.default}</a>
}
}
mrouter-view.js
export default {
render(h) {
let component = null; // 需要渲染的组件
// 动态获取需要渲染的组件
...
return h(component)
}
}
在mvue-router.js中全局注册这两个组件
import Link from './mrouter-link'
import View from './mrouter-view'
// 实现一个插件:挂载$router
class MVueRouter {
...
}
MVueRouter.install = function (_vue) {
let Vue = _vue
// 挂载$router
// 怎么获取根实例中获取router选项
// 利用全局或如,在beforCreate钩子里面获取选项
Vue.mixin({
// router只有在根实例中存在
beforeCreate () {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
// 声明两个全局组件
Vue.component('mrouter-link', Link)
Vue.component('mrouter-view', View)
}
export default MVueRouter
三、监听hashchange事件,管理url变化
- 在url发生变化时,在hashchange事件中取出当前的路由path
- 设置一个响应式的current属性与当前路由path一一映射
- 当current发生变化时,就可以触发依赖他的函数
mrouter-router.js主要代码
constructor(options) {
// 把options通过$options暴露出去 方便外部使用this.$router.$options
this.$options = options;
// 设置一个响应式的current属性
// Vue.util.defineReactive: 定义一个对象的响应属性
/**
* Vue.util.defineReactive(obj,key,value,fn)
obj: 目标对象,
key: 目标对象属性;
value: 属性值
fn: 只在node调试环境下set时调用
*/
Vue.util.defineReactive(this, 'current', '/')
// 监听hashchange事件
window.addEventListener('hashchange', this.onHashChange.bind(this))
// 加载的时候也执行一下
window.addEventListener('load', this.onHashChange.bind(this))
}
onHashChange() {
// 截取出#后面的path
this.current = window.location.hash.slice(1)
}
四、响应url的变化,渲染url对应的组件
前几步实现了路由的监听,并且将url进行了响应式处理,接下来就是对url对应的组件渲染出来,实现路由的跳转变换。
接下里在mrouter-view组件中实现
export default {
render(h) {
let component = null; // 需要渲染的组件
// 动态获取current对应的组件
// this指向当前实例
// $router.$options.routes 即: 路由配置数组
// $options是MVueRouter类暴露出来的option属性
this.$router.$options.routes.forEach(route => {
if (route.path === this.$router.current) {
component = route.component
}
});
return h(component)
}
}
<mrouter-view></mrouter-view>组件中动态获取$router中的current属性,current属性与roures路由配置进行匹配,从而动态拿到对应的组件。current属性是一个响应式的,与当前的路由一一映射,当它发生变化时自然会触发组件的渲染。
扫描二维码关注公众号,回复: 14850252 查看本文章
五、测试
App.vue
<template>
<div id="app">
<mrouter-link to="/403">403</mrouter-link>
<mrouter-link to="/404">404</mrouter-link>
<mrouter-view></mrouter-view>
<!-- <router-view></router-view> -->
</div>
</template>
router.js
import Vue from 'vue'
import MVueRouter from './plugin/mvue-router'
import routes from './route/index'
Vue.use(MVueRouter)
// 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes
})
// 创建和挂载根实例。
// 通过 router 配置参数注入路由,从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')