Vue.use(VueRouter)
=> 这是一个插件,需要实现一个静态方法 installnew VueRouter(options)
=> 需要实现一个class, Storethis.$router.xxx
=> 需要在页面上挂载$router<router-link to="/about"></router-link>
、 <router-view></router-view>
=> 需要实现2个全局组件: router-link
,router-view
router-link
组件,其实就是一个a标签,<a href="#/about">xxxxx</a>
router-view
组件,是一个容器,直接把需要展示的组件塞进去就行。 路由跳转,router-view更新 => 这里的存储路由的变量是响应式的$router
挂载: this.$options.router && (Vue.prototype.$router = this.$options.router),
如果this.$options.router
存在,就进行挂载。this.$options.router
这里是new Vue({router})传入的options,这个传参是在②中执行的,现在还在执行①的代码,就想把②的代码拿来用// 分析下 这个kRouter
// const router = new VueRouter({
// routes,
// });
// 1. Vue.use(kRouter) => 插件,是个class,需要加入install方法
// 2. 在页面中可以使用 this.$router => 需要挂载到Vue根实例的原型上
// 3. 需要实现页面跳转,且页面不刷新 => 1. hash模式 2. history Api 是H5的方法
// 4. 需要实现2个自定义组件 router-link 、 router-view
// 5. router-link => a标签 <router-link to="/home"/>
// 6. router-view => 一个容器,可以自动刷新组件的容器,根据值不同,自动进行视图更新 => 响应式(数据变化=> 页面更新, 页面更新=> 数据变化)
// 7. 在main.js中,先①引入router实例的代码,再②new VueRouter()传入store参数
// => ①import router时,先进行Vue.use(VueRouter),即执行install方法,在该方法中进行$router挂载: this.$options.router && (Vue.prototype.$router = this.$options.router), 如果this.$options.router存在,就进行挂载。this.$options.router 这里是new Vue({router})传入的options,这个传参是在②中执行的,现在还在执行①的代码,就想把②的代码拿来用
// 解决方案:
// ① 挂载$router放在setTimeout中,延迟执行 => 代码low、延迟时间不可控
// ② 使用Vue.mixin,在beforeCreate钩子函数中进行执行挂载,在beforeCreate执行时,new Vue({router})是一定执行了的,不然进不了这个钩子函数
// 在kRouter类中需要使用传入的形参Vue,所以需要定义变量保存一下
let Vue;
class KRouter {
constructor(options) {
this.$options = options;
// 实现页面不刷新跳转:用hash,监听hashchange事件
// ① 获取当前hash值; ② 监听hashchange事件
// 定义一个变量this.current,用来 1. 存储当前链接的hash值 2. 该current值发生变化,要求router-view组件内部的组件在页面是哪个随之更新 => 该current应该是个响应式数据
// this.current = window.location.hash.slice(1) || "/";
//Vue.util.defineReactive 是Vue隐藏的方法,是定义对象的某个属性为响应式数据
Vue.util.defineReactive(this, "current", {
get() {
return window.location.hash.slice(1) || "/";
},
});
// 获取routes对象,并将路由映射关系缓存起来
this.routeMap = {};
this.$options.routes.forEach((route) => {
this.routeMap[route.path] = route;
});
window.addEventListener("hashchange", this.onHashchange.bind(this)); // 这里的回调函数的this指向window,需要改变this的指向
window.addEventListener("load", this.onHashchange.bind(this));
}
onHashchange() {
this.current = window.location.hash.slice(1) || "/";
}
static install(_Vue) {
Vue = _Vue;
// 在页面中可以使用 this.$router => 需要挂载到Vue根实例的原型上
// 但是回到main.js中查看。先 import router, 然后再 用new Vue({router})进行vue实例化
// 细看具体代码,import router时,router的index.js中,① 先进行 vue.use(VueRouter),即 kRouter的静态方法 install,install方法中要将 KRouter的实例挂载到Vue构造函数的原型上,即Vue.prototype.$router上,② 但main.js中,是先import,后才将KRouter实例router传入new Vue({router})中。 => 先将 KRouter类的实例 router挂载在Vue实例上, 后才将KRouter类的实例 router传入Vue构造器中 => 这就不符合常理,先使用实例,后才将实例传入参数 => 解决方法 : ① 使用实例的时候(即将实例挂载到Vue原型上),用setTimeout进行延迟 => 有点low,且这个延迟时间也不好控制 ② 使用mixin的beforeCreate的方法,KRouter这个插件,也是vue的一个组件,同样可以使用mixin进行混入,在beforeCreate的生命周期中进行挂载的话,new Vue()一定是已经进行实例化的了。
Vue.mixin({
beforeCreate() {
// if (this.$options.router) 这个判断条件,是用来判断时Vue的跟组件实例化,还是,vue组件的实例化。 挂载$router,只需要在跟组件实例化的时候进行挂载就可以了,不需要所有的vue组件都进行挂载
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
// Vue.componet(‘组件名‘, 组件配置对象)
// <router-link to="/about">About</router-link> => <a href="#/about">xxxxxx</a>
// to=to="/about" 是组件的props,需要在自定义组件上添加props字段
Vue.component("router-link", {
// options: ① data(){return {}},props: [],template:‘<div></div>‘ 数据属性data 必须是一个返回值的函数。因为组件可能被用来创建多个实例,如果data是一个纯粹的对象,则所有的实例将会共享引用同一个数据对象!而通过data函数返回对象,则每次创建一个新实例以后,能调用data函数,返回一个全新的data对象
// options: ② render:h=>h(tag, props, children)
props: {
to: {
type: String,
required: true,
},
},
// props: [‘to‘],
render(h) {
// 注意: 这里不能使用箭头函数。 ? render:h => {} 使用箭头函数,这里的this是指向KRouter这个构造函数。而我们要使用的是,this能指向使用这个组件的组件实例
// children: this.$slots.default 默认插槽的内容
return h("a", {attrs: {href: "#" + this.to}}, this.$slots.default);
},
});
// <router-view></router-view>
// 1. hash改变 => router-view内的视图跟着改变
Vue.component("router-view", {
render: function (h) {
// 注意: 这里不能使用箭头函数。 ? render:h => {} 使用箭头函数,这里的this是指向KRouter这个构造函数。而我们要使用的是,this能指向使用这个组件的组件实例
// console.log(this);
const {current, routeMap} = this.$router;
const comp = (!!routeMap[current] && routeMap[current].component) || null;
// const comp = (!!this.$options.router && this.routeMap[this.current]) || null;
return h(comp);
},
});
}
}
export default KRouter;
原文:https://www.cnblogs.com/shine-lovely/p/14863877.html