一、vue.use源码分析
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
- 要点一:避免重复安装,首先会有检验是否已经安装过了,是的话,直接返回
- 要点二:
如果插件有install方法,则直接调用install方法
如果插件本身是一个方法,则直接运行
将已经安装的插件做记录,避免重复安装
二、vue封装插件的常用方法
1. 添加全局方法或属性,如vue-custom-element
MyPlugin.install = function (Vue, options) {
// 第一种方法. 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
}
}
注册方法
import registerCustomElement from './utils/registerCustomElement';
import { getProps, convertAttributeValue } from './utils/props';
function install(Vue) {
Vue.customElement = function vueCustomElement(tag, componentDefinition, options = {}) {
const isAsyncComponent = typeof componentDefinition === 'function';
const optionsProps = isAsyncComponent && { props: options.props || [] };
const props = getProps(isAsyncComponent ? optionsProps : componentDefinition);
// register Custom Element
const CustomElement = registerCustomElement(tag, {
// 相关操作
});
return CustomElement;
};
}
export default install;
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(install);
if (install.installed) {
install.installed = false;
}
}
使用方法
Vue.customElement('widget-vue', {
props: [
'prop1',
'prop2',
'prop3'
],
data: {
message: 'Hello Vue!'
},
template: '<p>{{ message }}, {{ prop1 }}, {{prop2}}, {{prop3}}</p>'
});
<widget-vue prop1="1" prop2="string" prop3="true"></widget-vue>
2. 添加全局资源:指令/过滤器/过渡等,如:vue-touch
vueTouch.install = function (Vue) {
Vue.directive('touch', {
isFn: true,
acceptStatement: true,
priority: Vue.directive('on').priority,
bind: function () {
// 绑定时的操作
},
update: function (fn) {
// 更新时的操作
},
unbind: function () {
// 解绑时的操作
}
})
}
3. 通过mixin方法添加一些组件选项,如vue-router
插件内部定义:
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
外部使用:
new Vue({
router,
render: h => h(App),
}).$mount('#app')
所以每个组件在执行beforeCreate生命周期的时候,都会执行this._router.init(this)
4. 添加Vue实例方法,通过把他们添加到Vue.prototype上实现
Vue.prototype.$myMethod = function (methodOptions)
{ // 逻辑... }
5. 全局注册组件,如elementUI
// 第六种方法,注册组件
Vue.component(组件名, 组件)
三、开放封闭原则
对拓展开放,意味着有新的需求或变化是,可以对现有代码进行扩展,以适应新的情况
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改
规则建议:
1、开放封闭原则,是最为重要的设计原则,Liskov替换原则和合成/聚合复用原则为开放封闭原则的实现提供保证。
2、可以通过Template Method模式和Strategy模式进行重构,实现对修改封闭、对扩展开放的设计思路。
3、封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态一般将其封装为一个抽象,例如银行业务中的IBankProcess接口。
4、拒绝滥用抽象,只将经常变化的部分进行抽象,这种经验可以从设计模式的学习与应用中获得。
四、插件的开发原则
- 插件对外暴露的参数应保持最少原则,聚焦使用者关注点
- 插件或组件的实现应该要基于使用场景考虑
- 开发一款组件或插件,应该保持软件工程领域的开放封闭原则
- 一款好的插件或组件不是一蹴而就的,,往往需要后期使用过程中发现问题,加以改善
-
- 组件或者插件的文档一定要完善,并不是每一个使用它的人,都关心它的内部实现,他们更关心的可能仅是如何快速上手
五、核心代码
toast插件
只可以通过函数式进行调用
import Toast from './component'
import { iconsMap, titleMap } from './config'
const ToastPlugin = {
install (Vue, options = {}) {
const ToastConstructor = Vue.extend(Toast)
Vue.prototype.$toast = toast
function buildProps (args) {
let props = {}
// 配置项操作
return props
}
function toast () {
if (!arguments[0]) return
const propsData = buildProps(arguments)
const instance = new ToastConstructor({ propsData })
document.body.appendChild(instance.$mount().$el)
}
}
}
export default ToastPlugin
文字输入包括表情插件
import Emoji from './App.vue'
const components = [
Emoji
]
const install = function (Vue, opts = {}) {
components.map(component => {
Vue.component(component.name, component);
})
}
/* 支持使用标签的方式引入 */
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
install,
Emoji
}
vue.use安装插件的时候,会直接执行install方法,即进行了全局注册,便可以通过标签进行调用了(elementUI)