前言
我们在使用Vue的时候,经常会使用并写一些自定义的插件,然后利用Vue.use引入。所以提到写插件,install这个方法是必不可少的。Vue.js 的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象。这是Vue官方对Vue插件的规范。那这install函数到底是什么东东呢,Vue内部到底用它做了什么处理,怎么调用的,今天我就给大家伙从源码层面把他整的明明白白。
看完这篇文章,你将学到:
install函数可以做些什么;
install内部是怎么实现的;
Vuex,Vue-Router插件在install期间到底干了什么;
好啦,闲话不多说,咱们直接开始!!!
install在Vuex&Vue-Router中的处理
这里先抛出两个问题,大家可以思考下,算是挖坑,下面再逐一解答:
为什么我们在项目中可以直接使用$router $store来获取其中的值以及一些方法;
为什么使用这俩插件都是先用Vue.use引入。然后才创建实例,在Vue实例中传入;
二者其实原理相同,这里我们用Vue-Router来举例,首先我们来看一下它内部install的具体实现:
class Router {
constructor(options) {
…
}
}
Router.install = function(_Vue) {
_Vue.mixin({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
}
}
})
}
export default Router;
_Vue.mixin全局混入是什么呢?相当于在所有的组件中混入这个方法;
beforeCreate是什么呢?当然是Vue的一个生命周期,在create之前执行;
既然如此,我们大胆的做一个判断。Vue-Router其实是在install函数里面使用了一个全局混入,在beforeCreate这个生命周期触发的时候把this. o p t i o n s . r o u t e r 挂 载 到 V u e 的 原 型 上 , 这 样 我 们 就 可 以 使 用 t h i s . options.router挂载到Vue的原型上,这样我们就可以使用this. options.router挂载到Vue的原型上,这样我们就可以使用this.router来调用router实例啦。
同学A:等一下,stop!!!你说的我很李姐,但是this.$options.router这又是什么东西,从哪来的啊?
安啦,这咱们才刚刚解决了第一个问题,下面咱们来填第二个坑。
咱们平时使用Vue-Router,以及定义入口文件的Vue实例大概是这样子
// router/index.js
import VueRouter form ‘vue-router’;
import Vue from ‘vue’;
Vue.use(VueRouter);
const _router = [
…
]
const Router = new VueRouter(_router);
export default Router;
// main.js
import Vue from ‘vue’;
import router from ‘router’;
new Vue({
router,
…
}).$mount(’#app’);
结合最开始的例子,我们先来分析一波。
Vue.use()主要是调用插件内部的install方法,并将Vue实例作为参数传入;
上面使用的是this. o p t i o n s . r o u t e r , o p t i o n s 通 常 代 表 的 是 配 置 项 ; 在 m a i n . j s 中 我 们 把 R o u t e r 实 例 作 为 配 置 项 传 入 到 V u e 实 例 中 叮 ! ! ! 要 素 察 觉 , 那 我 们 来 大 胆 推 测 一 波 。 V u e − R o u t e r 先 u s e 其 实 是 做 了 一 个 全 局 混 入 , 为 了 在 合 适 的 时 间 点 , 获 取 到 V u e 根 实 例 配 置 项 中 的 r o u t e r 实 例 , 执 行 挂 载 。 紧 接 着 在 n e w V u e ( ) 根 实 例 创 建 的 时 候 , 注 入 r o u t e r 实 例 , 然 后 触 发 全 局 混 入 中 的 生 命 周 期 , 这 个 时 候 根 实 例 的 配 置 项 t h i s . options.router,options通常代表的是配置项; 在main.js中我们把Router实例作为配置项传入到Vue实例中 叮!!!要素察觉,那我们来大胆推测一波。 Vue-Router先use其实是做了一个全局混入,为了在合适的时间点,获取到Vue根实例配置项中的router实例,执行挂载。紧接着在new Vue()根实例创建的时候,注入router实例,然后触发全局混入中的生命周期,这个时候根实例的配置项this. options.router,options通常代表的是配置项;在main.js中我们把Router实例作为配置项传入到Vue实例中叮!!!要素察觉,那我们来大胆推测一波。Vue−Router先use其实是做了一个全局混入,为了在合适的时间点,获取到Vue根实例配置项中的router实例,执行挂载。紧接着在newVue()根实例创建的时候,注入router实例,然后触发全局混入中的生命周期,这个时候根实例的配置项this.options已经包含了router实例,最后完成挂载流程!!!
光这一段的代码也是逻辑缜密,编程思路巧妙,令人直呼内行啊!兄弟萌,把内行打在公屏上,hhhh。
install在Vue中的内部实现
看完了常用库install的使用,不知大家是否有收获。接下来热身结束后,我们就可以开始看一看install内部实现了,先上源码。
export function initUse (Vue: GlobalAPI) {
// 注册一个挂载在实例上的use方法
Vue.use = function (plugin: Function | Object) {
// 初始化当前插件的数组
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
// 如果这个插件已经被注册过了,那就不作处理
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
...
// 重点来了哦!!!
if (typeof plugin.install === 'function') {
// 当插件中install是一个函数的时候,调用install方法,指向插件,并把一众参数传入
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
// 当插件本身就是一个函数的时候,把它当做install方法,指向插件,并把一众参数传入
plugin.apply(null, args)
}
// 将插件放入插件数组中
installedPlugins.push(plugin)
return this
}
}
源码这部分写的很简洁,可读性很高。就是在use的时候,判断插件类型,执行install或者插件本身。其实细化一下官网的解释就是,Class类的插件应该暴露一个 install 方法。
结语
这次的分享到这里就结束啦,不知道大家对于Vue的插件机制有没有更深入的了解呢?其实开发插件的时候利用install我们可以做茫茫多的事儿。
比如Vue-Router在install中其实还注册了Router-view和Router-link的全局组件。感兴趣的同学们可以去看一下vue-router的原理?我们来手撸一个vue-router!
再次感谢你的阅读。好啦,兄弟萌再见咯!
作者:Ekko_
链接:https://segmentfault.com/a/1190000022802059
来源:SegmentFault 思否
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。