router任务分析
解析routes选项
使用 vue-router
时,需要创建一个 .js
后缀的文件,该文件内会出现下列代码,即声明 vue
安装了该插件,但是在初学 vue
时,你会发现mian.js中存在如下代码,那么为何安装了插件同时还要在根实例上配置 router
实例
# router.js
...
Vue.use(Router);
...
# main.js
...
new Vue({
data: {
bar: 'bar'
},
router, // 【此处重点】配置router实例
store,
render: h => h(App)
}).$mount("#app");
监控URL变化、实现全局组件(router-link、router-view)
两种方式:一种 history【监听历史记录改变】,一种监听 hash 改变
html5 history api -- xx.html/login
hash xx.html#/login
注意:声明Vue插件需求实现一个install的静态方法)
let Vue; // 保存Vue构造函数引用
class KVueRouter {
constructor(options) {
this.$options = options;
this.routeMap = {}; // {'/index': { component:Index,... }}
// 当前url需要是响应式的
this.vm = new Vue({
data: { current: '/' }
});
}
// 初始化
init() {
// 监听事件
this.bindEvents();
// 解析routers
this.createRouteMap();
// 声明组件
this.initComponent();
}
bindEvents() {
window.addEventListener('hashchange', this.onHashchange.bind(this))
}
onHashchange() {
this.app.current = window.location.hash.slice(1) || '/'
}
createRouteMap() {
// 遍历用户配置路由数组
this.$options.routes.forEach(item => {
this.routeMap[item.path] = route;
});
}
initComponent() {
// 转换目标: <a href="/">xxx</a>
// <router-link to="/">
Vue.component('router-link', {
props: {
to: String,
},
render(h) {
// h(tag, data, children)
// 使用createElement函数
return h('a', {
attrs: { href: '#' + this.to }
}, [this.$slots.default)]);
// 使用jsx
// return <a href={'#' + this.to}>{this.$slots.default}}</a>;
}
})
}
}
// 参数是Vue构造函数
KVueRouter.install = function(_Vue) {
Vue = _Vue;
/* 为何不直接在此处定义$router,而舍近求远的建立一个混合呢?
Vue.use(Router) 是定义在router.js文件夹的,此时vue实例尚未初始化,this无法获取到实例。
Vue.prototype.$router = this.$options.router;
*/
// 实现一个混入
Vue.mixin({
beforeCreate() {
// this.$optinos 获取当前Vue实例的初始化选项【对象参数】。需要在选项中包含自定义属性时会有用处:
// 获取KVueRouter实例并挂载到Vue.prototype
if (this.$options.router) {
/* 只在根组件beforeCreate时执行一次、
这也是为什么根组件初始化对象中含有router属性
new Vue({
data: {
bar: 'bar'
},
router, // 配置router实例
store,
render: h => h(App)
}).$mount("#app");
*/
Vue.prototype.$router = this.$options.router;
}
}
})
}