Vue 插件編寫與實戰

關於

  • 微信公眾號:前端呼啦圈(Love-FED)
  • 我的博客:勞卜的博客
  • 知乎專欄:前端呼啦圈

前言

熱愛vue開發的同學肯定知道awesome-vue 這個github地址,裡面包含了數以千計的vue開源插件,而這些插件大都來自第三方開發者們,是他們為vue社區提供了大量的技術支持和解決方案。本文立足vue開源的理念,主要為vue開發者講解編寫vue插件的方法和步驟,通過理論與實踐相結合的方式來加深大家對vue插件編寫的認識。

vue插件介紹

1. 插件與組件

在講解插件之前,我們首先來了解下vue插件和組件的關係,在我們的vue項目中我們使用組件的頻率往往會大於插件,關係如下圖所示:

在沒有封裝組件之前,如果不使用第三方插件,那麼很多情況下我們會編寫幾個常用的組件來提供給頁面使用,如Alert/Loading組件,而你可能需要在很多頁面中引入並且通過components註冊組件,但是像這樣使用率很高的組件一般我們希望全局註冊後直接就可以在相應頁面使用,因此我們需要將他們封裝成插件,比如像vux這樣的ui組件庫,即提供了組件功能也提供了某些全局註冊的插件。

用一句話簡單概括兩者的關係就是:插件可以封裝組件,組件可以暴露數據給插件。

2. 插件分類

vue插件的編寫方法一般分為4類,如上圖所示。主要註冊與綁定機制如下:

export default {n install(Vue, options) {n Vue.myGlobalMethod = function () { // 1. 添加全局方法或屬性,如: vue-custom-elementn // 邏輯...n }nn Vue.directive(my-directive, { // 2. 添加全局資源:指令/過濾器/過渡等,如 vue-touchn bind (el, binding, vnode, oldVnode) {n // 邏輯...n }n ...n })nn Vue.mixin({n created: function () { // 3. 通過全局 mixin方法添加一些組件選項,如: vuexn // 邏輯...n }n ...n }) nn Vue.prototype.$myMethod = function (options) { // 4. 添加實例方法,通過把它們添加到 Vue.prototype 上實現n // 邏輯...n }n }n}n

上方代碼使用了es6部分語法列出了4種編寫插件的方法,而install是註冊插件主要調用的方法,包含了兩個參數(Vue實例和自定義配置屬性options),我們可以將以上代碼存儲到plugins.js中。

3. 插件使用

在plugins.js中我們僅僅編寫了一個插件的空殼子,假如現在需要全局註冊該插件,我們可以在入口文件,比如main.js中註冊:

...nnimport Vue from vuenimport MyPlugin from ./plugins/plugins.jsnnVue.use(MyPlugin);nn...n

通過全局方法 Vue.use() 即可使用該插件,其自動會調用install方法。Vue.use會自動阻止註冊相同插件多次,屆時只會註冊一次該插件。

vue插件編寫方法

上述我們提到了編寫插件的4種方法,接下來我們對其一一進行講解:

1. 添加全局方法或屬性

export default {n install(Vue, options) {n Vue.$myName = 勞卜;n }n}n

在install方法中,我們直接在Vue實例上聲明了$myName屬性並進行了賦值,當該插件註冊後只要存在Vue實例的地方你都可以獲取到Vue.$myName的值,因為其直接綁定在了Vue實例上。

2. 添加全局資源

export default {n install(Vue, options) {n Vue.directive(focus, {n bind: function() {},nn // 當綁定元素插入到 DOM 中。n inserted: function(el, binding, vnode, oldVnode) {nn // 聚焦元素n el.focus();n },nn update: function() {},n componentUpdated: function() {},n unbind: function() {}n });n },n}n

添加全局資源包含了添加全局的指令/過濾器/過渡等,上方代碼我們通過Vue.directive()添加了一個全局指令v-focus,其主要包含了5種方法,其中inserted代表當綁定元素插入到 DOM 中執行,而el.focus()代表聚焦綁定的元素,這樣如果我們在一個input輸入框上綁定該指令就會自動進行focus聚焦。

其他directive提供的方法及用途可以參考:vue自定義指令

3. 添加全局mixin方法

export default {n install(Vue, options) {n Vue.mixin({n methods: {n greetingFn() {n console.log(greeting);n }n }n });n },n}n

mixin代表混合的意思,我們可以全局註冊一個混合,其會影響註冊之後創建的每個 Vue 實例,上方代碼註冊後會在每個組件實例中添加greetingFn方法,在單文件組件中可以直接通過this.greetingFn()調用。當然如果實例中存在同名方法,則mixin方法中創建的會被覆蓋,同時mixin對象中的鉤子將在組件自身鉤子之前調用。

4. 添加實例方法

export default {n install(Vue, options) {n Vue.prototype.$myName = 勞卜;n Vue.prototype.showMyName = value => {n console.log(value);n };n },n}n

添加實例方法是最常用的一種方法,其直接綁定在vue的原型鏈上,我們可以回想一下 JS 里的類的概念。實例方法可以在組件內部,通過this.$myMethod來調用。

5. 插件封裝組件

上方4點只講解了插件自身的4中編寫方法,並沒有涉及組件的內容,如果我們要在組件的基礎上編寫插件,我們可以使用Vue.extend(component)來進行,可以見下方loading插件實例。

loading插件

<!-- loading.vue組件 -->n<template>n <div class="loading-box" v-show="show">n <div class="loading-mask"></div>n <div class="loading-content">n <div class="animate">n </div>n <div class="text">{{text}}</div>n </div>n </div>n</template>nn<script>nexport default {n props: {n show: Boolean,n text: {n type: String,n default: 正在載入中...n },n }n}n</script>n

以上是一個loading.vue組件,省略了樣式部分,在沒有封裝插件之前,我們只能通過import引入並註冊到components對象中才能在頁面中使用,如:

<template>n <div>n <loading :show="true"></loading>n </div>n</template>n<script>nimport Loading from ./loading.vuennexport default {n ...nn components: {n Loadingn }nn ...n}n</script>n

下面我們便來封裝一下該組件:

// loading.jsnimport LoadingComponent from ../components/loading.vuennlet $vmnnexport default {n install(Vue, options) {n if (!$vm) {n const LoadingPlugin = Vue.extend(LoadingComponent);nn $vm = new LoadingPlugin({n el: document.createElement(div)n });nn document.body.appendChild($vm.$el);n }nn $vm.show = false;nn let loading = {n show(text) {n $vm.show = true;nn $vm.text = text;n },n hide() {n $vm.show = false;n }n };nn if (!Vue.$loading) {n Vue.$loading = loading;n }nn // Vue.prototype.$loading = Vue.$loading;nn Vue.mixin({n created() {n this.$loading = Vue.$loading;n }n })n }n}n

以上我們新建一個loading.js文件,引入我們的loading.vue組件,然後通過Vue.extend()方法創建了一個構造器LoadingPlugin,其次我們再通過new LoadingPlugin()創建了$vm實例,並掛載到一個div元素上。最後我們需要通過document.body.appendChild($vm.$el)將其插入到DOM節點中。

當我們創建了$vm實例後,我們可以訪問該實例的屬性和方法,比如通過$vm.show就可以改變loading組件的show值來控制其顯示隱藏。

最終我們通過Vue.mixin或者Vue.prototype.$loading來全局添加了$loading事件,其又包含了show和hide兩個方法。我們可以直接在頁面中使用this.$loading.show()來顯示載入,使用this.$loading.hide()來關閉載入。

插件發布

插件編寫完後我們的目的除了本地引用註冊外,可能更希望發布到線上供他人或其他項目使用,因此我們需要了解插件發布的方法。

1. 發布準備

在發布插件前你需要一個npm賬號,你可以訪問:npmjs.com/ 進行註冊

2. 發布命令

npm loginncd 目錄nnpm publishn

擁有賬號後,你需要在控制台輸入npm login命令來登錄你的賬號,並且輸入郵箱地址。然後打開你的插件目錄,允許npm publish發布。最簡單的一個插件目錄如下:

3. 發布目錄

├── lib // 插件源碼n ├── components // 組件目錄n └── loading.vue // 組件文件n └── index.js // 插件入口文件n├── index.js // 入口文件n└── package.json // 包管理文件n

你可以在項目中安裝剛剛的loading插件來進行參考,我已經發布至npm:

npm install super-loading --saven

當然你也可以訪問github倉庫:github.com/luozhihao/su 進行下載。

結語

本文的最終目的並不是教大家如何去編寫一個loading插件,而是幫助大家了解在編寫插件的過程中所使用的技巧和方法,只有掌握了技巧和方法才能寫出各種各樣的插件,正所謂水到自然渠成。

如果覺得本文對你有幫助,可以關注我的微信公眾號,來這裡聊點關於前端的事情。

推薦閱讀:

最近的一次討論記錄

TAG:Vuejs | 前端开发 | 前端框架 |