插件编写的基本方法
推荐大家先看看官方给出的插件使用和开发方法 https://vuejs.bootcss.com/guide/plugins.html ?
需求分析
我们先看看vue-router 的使用步骤
-
use Vue.use(VueRouter) 注意??: Vue.use() 主要是调用插件内部的install方法,并将Vue实例作为参数传入 ? -
new 一个router实例 const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
-
new Vue() ,把实例放在vue的配置项里面 new Vue({
router,
render: h => h(App)
}).$mount('#app')
-
使用路由组件<router-view/> 、<router-link></router-link> 或者在组件中使用this.$router
由此我们看看vue-router内部做了什么?
- 将$router挂载到全局上
- 实现并声明了两个组件:
<router-view/> 、<router-link></router-link>
?
实现思路
首先我们看看如何将$router 挂载到组件上
?
let Vue;
VueRouter.install = function (_Vue) {
Vue = _Vue;
console.log("options", Vue.$options);
Vue.mixin({
beforeCreate() {
console.log("inner", this);
console.log(" this.$options.router", this.$options.router);
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
console.log("end");
};
可以看到: 1、第一次执行的时候,即在Vue.use(Router)时,还没有实例化vue(因为Vue.use() 发生在 new Vue() 之前),所以Vue.$option本身是拿不到的(ps: option就是new Vue() 时传入的参数,router也往里面传),此时既然拿不到router的实例,所以不能直接在install方法里面挂载; ?
?
2、我们可以在use的时候做一个全局混入,在合适的时间点,获取到Vue根实例配置项中的router实例, 执行挂载。紧接着在new Vue()根实例创建的时候,因为注入了router实例,所以再执行全局混入(mixin)中的生命周期时,这个时候根实例的配置项this.$options 已经包含了router实例,可以此时把router挂载到Vue的原型上。之后所有Vue实例扩展来的VueCompont都可以通过this.$router 访问到这个属性
?
如何实现那两个路由组件
先看看路由组件如何使用
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
由上面可以看出,点击router-link ,就相当于点了a标签,然后a标签的href属性控制页面路由发生了变化;监听路由变化,然后仔router-view里面输出不同的模板; ?
而路由变化有两种方式
hash模式 :
使用 URL 的 hash 来模拟一个完整的 URL, 其显示的网络路径中会有 “#” 号 hash 虽然出现URL中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash后刷新, 也不会有问题 hash模式示例: http://localhost:8080/#/home http://localhost:8080/#/user hash详解: hashChange ?
history模式:
美化后的hash模式,路径中不包含“#”。依赖于Html5 的** history api** 由于改变了地址, 刷新时会按照修改后的地址请求后端, 需要后端配置处理, 将地址访问做映射, 否则会404; history模式示例: http://localhost:8080/home http://localhost:8080/user history 监听路由: popState, pushState() history模式监听路由分两种情况,一种是直接监听popstate事件刷新页面组件,这个只适合网页首次访问、浏览器的前进和后退的情况,因为history.pushState()或history.replaceState()不会触发popstate事件。另一种就是通过router.push、router.replace来改变url地址,这时候,在这两个api的内部实际上也分了两步走:
- 页面组件更新(即更新router的current属性)
- 底层调用history.pushState/history.replaceState改变url
?
我们来实现一个简单的hash式的路由变化
大伙儿不知道怎么注册全局组件的话,最好先看看下面这个 组件基础搭建
先来看看router-link
Vue.component("router-link", {
props: {
to: {
required: true,
},
},
render(h) {
return h(
"a",
{
attrs: { href: "#" + this.to },
},
this.$slots.default
);
},
});
?
再来看看router-view
class VueRouter {
constructor(options) {
this.$options = options;
const initial = "/";
Vue.util.defineReactive(this, "current", initial);
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1);
});
}
}
VueRouter.install = function (_Vue) {
Vue = _Vue;
Vue.component("router-view", {
render(h) {
const { current, $options } = this.$router;
const route = $options.routes.find((item) => {
return item.path === current;
});
let component = route ? route.component : null;
return h(component);
},
});
}
图一
完整demo代码
let Vue;
class VueRouter {
constructor(options) {
this.$options = options;
const initial = "/";
Vue.util.defineReactive(this, "current", initial);
this.current = "/";
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1);
});
}
}
VueRouter.install = function (_Vue) {
Vue = _Vue;
console.log("options", this);
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
Vue.component("router-link", {
props: {
to: {
required: true,
},
},
render(h) {
return h(
"a",
{
attrs: { href: "#" + this.to },
},
this.$slots.default
);
},
});
Vue.component("router-view", {
render(h) {
const { current, $options } = this.$router;
const route = $options.routes.find((item) => {
return item.path === current;
});
let component = route ? route.component : null;
return h(component);
},
});
};
export default VueRouter;
|