前言
熱愛vue開發(fā)的同學(xué)肯定知道awesome-vue 這個github地址蜡娶,里面包含了數(shù)以千計的vue開源插件,而這些插件大都來自第三方開發(fā)者們母廷,是他們?yōu)関ue社區(qū)提供了大量的技術(shù)支持和解決方案斑举。本文立足vue開源的理念,主要為vue開發(fā)者講解編寫vue插件的方法和步驟脊奋,通過理論與實踐相結(jié)合的方式來加深大家對vue插件編寫的認(rèn)識熬北。
vue插件介紹
1. 插件與組件
在講解插件之前,我們首先來了解下vue插件和組件的關(guān)系诚隙,在我們的vue項目中我們使用組件的頻率往往會大于插件讶隐,關(guān)系如下圖所示:
在沒有封裝組件之前,如果不使用第三方插件久又,那么很多情況下我們會編寫幾個常用的組件來提供給頁面使用巫延,如Alert/Loading組件,而你可能需要在很多頁面中引入并且通過components注冊組件地消,但是像這樣使用率很高的組件一般我們希望全局注冊后直接就可以在相應(yīng)頁面使用炉峰,因此我們需要將他們封裝成插件,比如像vux這樣的ui組件庫脉执,即提供了組件功能也提供了某些全局注冊的插件讲冠。
用一句話簡單概括兩者的關(guān)系就是:插件可以封裝組件,組件可以暴露數(shù)據(jù)給插件适瓦。
2. 插件分類
vue插件的編寫方法一般分為4類竿开,如上圖所示。主要注冊與綁定機制如下:
export default {
install(Vue, options) {
Vue.myGlobalMethod = function () { // 1. 添加全局方法或?qū)傩圆N酰? vue-custom-element
// 邏輯...
}
Vue.directive('my-directive', { // 2. 添加全局資源:指令/過濾器/過渡等否彩,如 vue-touch
bind (el, binding, vnode, oldVnode) {
// 邏輯...
}
...
})
Vue.mixin({
created: function () { // 3. 通過全局 mixin方法添加一些組件選項,如: vuex
// 邏輯...
}
...
})
Vue.prototype.$myMethod = function (options) { // 4. 添加實例方法嗦随,通過把它們添加到 Vue.prototype 上實現(xiàn)
// 邏輯...
}
}
}
上方代碼使用了es6部分語法列出了4種編寫插件的方法列荔,而install是注冊插件主要調(diào)用的方法敬尺,包含了兩個參數(shù)(Vue實例和自定義配置屬性options),我們可以將以上代碼存儲到plugins.js中贴浙。
3. 插件使用
在plugins.js中我們僅僅編寫了一個插件的空殼子砂吞,假如現(xiàn)在需要全局注冊該插件,我們可以在入口文件崎溃,比如main.js中注冊:
...
import Vue from 'vue'
import MyPlugin from './plugins/plugins.js'
Vue.use(MyPlugin);
...
通過全局方法 Vue.use() 即可使用該插件蜻直,其自動會調(diào)用install方法。Vue.use會自動阻止注冊相同插件多次袁串,屆時只會注冊一次該插件概而。
vue插件編寫方法
上述我們提到了編寫插件的4種方法,接下來我們對其一一進(jìn)行講解:
1. 添加全局方法或?qū)傩?/h3>
export default {
install(Vue, options) {
Vue.$myName = '勞卜';
}
}
export default {
install(Vue, options) {
Vue.$myName = '勞卜';
}
}
在install方法中囱修,我們直接在Vue實例上聲明了$myName屬性并進(jìn)行了賦值赎瑰,當(dāng)該插件注冊后只要存在Vue實例的地方你都可以獲取到Vue.$myName的值,因為其直接綁定在了Vue實例上破镰。
2. 添加全局資源
export default {
install(Vue, options) {
Vue.directive('focus', {
bind: function() {},
// 當(dāng)綁定元素插入到 DOM 中餐曼。
inserted: function(el, binding, vnode, oldVnode) {
// 聚焦元素
el.focus();
},
update: function() {},
componentUpdated: function() {},
unbind: function() {}
});
},
}
添加全局資源包含了添加全局的指令/過濾器/過渡等,上方代碼我們通過Vue.directive()添加了一個全局指令v-focus鲜漩,其主要包含了5種方法晋辆,其中inserted代表當(dāng)綁定元素插入到 DOM 中執(zhí)行,而el.focus()代表聚焦綁定的元素宇整,這樣如果我們在一個input輸入框上綁定該指令就會自動進(jìn)行focus聚焦。
其他directive提供的方法及用途可以參考:vue自定義指令
3. 添加全局mixin方法
export default {
install(Vue, options) {
Vue.mixin({
methods: {
greetingFn() {
console.log('greeting');
}
}
});
},
}
mixin代表混合的意思芋膘,我們可以全局注冊一個混合鳞青,其會影響注冊之后創(chuàng)建的每個 Vue 實例,上方代碼注冊后會在每個組件實例中添加greetingFn方法为朋,在單文件組件中可以直接通過this.greetingFn()調(diào)用臂拓。當(dāng)然如果實例中存在同名方法,則mixin方法中創(chuàng)建的會被覆蓋习寸,同時mixin對象中的鉤子將在組件自身鉤子之前調(diào)用胶惰。
4. 添加實例方法
export default {
install(Vue, options) {
Vue.prototype.$myName = '勞卜';
Vue.prototype.showMyName = value => {
console.log(value);
};
},
}
添加實例方法是最常用的一種方法,其直接綁定在vue的原型鏈上霞溪,我們可以回想一下 JS 里的類的概念孵滞。實例方法可以在組件內(nèi)部,通過this.$myMethod來調(diào)用鸯匹。
5. 插件封裝組件
上方4點只講解了插件自身的4中編寫方法坊饶,并沒有涉及組件的內(nèi)容,如果我們要在組件的基礎(chǔ)上編寫插件殴蓬,我們可以使用Vue.extend(component)來進(jìn)行匿级,可以見下方loading插件實例。
loading插件
<!-- loading.vue組件 -->
<template>
<div class="loading-box" v-show="show">
<div class="loading-mask"></div>
<div class="loading-content">
<div class="animate">
</div>
<div class="text">{{text}}</div>
</div>
</div>
</template>
<script>
export default {
props: {
show: Boolean,
text: {
type: String,
default: '正在加載中...'
},
}
}
</script>
以上是一個loading.vue組件,省略了樣式部分痘绎,在沒有封裝插件之前津函,我們只能通過import引入并注冊到components對象中才能在頁面中使用,如:
<template>
<div>
<loading :show="true"></loading>
</div>
</template>
<script>
import Loading from './loading.vue'
export default {
...
components: {
Loading
}
...
}
</script>
下面我們便來封裝一下該組件:
// loading.js
import LoadingComponent from '../components/loading.vue'
let $vm
export default {
install(Vue, options) {
if (!$vm) {
const LoadingPlugin = Vue.extend(LoadingComponent);
$vm = new LoadingPlugin({
el: document.createElement('div')
});
document.body.appendChild($vm.$el);
}
$vm.show = false;
let loading = {
show(text) {
$vm.show = true;
$vm.text = text;
},
hide() {
$vm.show = false;
}
};
if (!Vue.$loading) {
Vue.$loading = loading;
}
// Vue.prototype.$loading = Vue.$loading;
Vue.mixin({
created() {
this.$loading = Vue.$loading;
}
})
}
}
以上我們新建一個loading.js文件孤页,引入我們的loading.vue組件尔苦,然后通過Vue.extend()方法創(chuàng)建了一個構(gòu)造器LoadingPlugin,其次我們再通過new LoadingPlugin()創(chuàng)建了$vm實例散庶,并掛載到一個div元素上蕉堰。最后我們需要通過document.body.appendChild($vm.$el)將其插入到DOM節(jié)點中。
當(dāng)我們創(chuàng)建了$vm實例后悲龟,我們可以訪問該實例的屬性和方法屋讶,比如通過$vm.show就可以改變loading組件的show值來控制其顯示隱藏。
最終我們通過Vue.mixin或者Vue.prototype.$loading來全局添加了$loading事件须教,其又包含了show和hide兩個方法皿渗。我們可以直接在頁面中使用this.$loading.show()來顯示加載,使用this.$loading.hide()來關(guān)閉加載轻腺。
插件發(fā)布
插件編寫完后我們的目的除了本地引用注冊外乐疆,可能更希望發(fā)布到線上供他人或其他項目使用,因此我們需要了解插件發(fā)布的方法贬养。
1. 發(fā)布準(zhǔn)備
在發(fā)布插件前你需要一個npm賬號挤土,你可以訪問:https://www.npmjs.com/ 進(jìn)行注冊
2. 發(fā)布命令
npm login
cd 目錄
npm publish
擁有賬號后,你需要在控制臺輸入npm login命令來登錄你的賬號误算,并且輸入郵箱地址仰美。然后打開你的插件目錄,允許npm publish發(fā)布儿礼。最簡單的一個插件目錄如下:
3. 發(fā)布目錄
├── lib // 插件源碼
│ ├── components // 組件目錄
│ │ └── loading.vue // 組件文件
│ └── index.js // 插件入口文件
├── index.js // 入口文件
└── package.json // 包管理文件
你可以在項目中安裝剛剛的loading插件來進(jìn)行參考咖杂,我已經(jīng)發(fā)布至npm:
npm install super-loading --save
當(dāng)然你也可以訪問github倉庫:https://github.com/luozhihao/super-loading 進(jìn)行下載。
結(jié)語
本文的最終目的并不是教大家如何去編寫一個loading插件蚊夫,而是幫助大家了解在編寫插件的過程中所使用的技巧和方法诉字,只有掌握了技巧和方法才能寫出各種各樣的插件,正所謂水到自然渠成知纷。