手牽手教你寫 Vue 插件

碎碎念

上一篇文章,咱們介紹瞭如何構建一個 react 插件,今天咱們說說如何構建 vue 插件css

準備工做

因爲與上一篇 react 插件文章使用的是相同的結構,代碼測試、持續集成及發佈 npm 包也都是一個套路,這裏就再也不敖述。 下面主要說下不一樣的地方,let's start 😊html

  1. 開發依賴包
{
    "devDependencies": {
        "@babel/core": "^7.0.0",
        "@babel/preset-env": "^7.0.0",
        "babel-loader": "^8.0.2",
        "chai": "^4.2.0",
        "coveralls": "^3.0.2",
        "css-loader": "^1.0.0",
        "jest": "^23.6.0",
        "style-loader": "^0.23.1",
        "vue": "^2.5.21",
        "vue-loader": "^15.5.0", // 解析 SFC 文件
        "vue-style-loader": "^4.1.2",
        "vue-template-compiler": "^2.5.21", // vue-loader 的同步依賴 
        "webpack": "^4.17.2",
        "webpack-cli": "^3.1.0"
    },
}
複製代碼
  1. webpack 配置
const path = require('path');
const { VueLoaderPlugin } = require("vue-loader");

module.exports = {
    mode: "production", // 生產模式
    entry: { // 入口
        "YanProgress": path.resolve(__dirname, './src/index.js')
    },
    output: { // 出口
        path: path.resolve(__dirname, './dist'),
        filename: '[name].min.js',
        publicPath: "./dist/",
        libraryTarget: 'umd', // 按 UMD 模式打包
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    // 模板編譯過程當中,編譯器能夠將某些特性轉換爲 require 調用
                    transformAssetUrls: {
                        video: ['src', 'poster'],
                        source: 'src',
                        img: 'src',
                        image: 'xlink:href' // SVG
                    }
                },
                // 只命中src目錄裏的js文件,加快 Webpack 搜索速度
                include: path.resolve(__dirname, "./src"),
            },
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env']
                        }
                    },
                ],
                // 只命中src目錄裏的js文件,加快 Webpack 搜索速度
                include: path.resolve(__dirname, "./src/"),
            },
            {

                test: /\.css$/,
                loader: "style-loader!css-loader"
            }
        ]
    },
    plugins: [
        // vue-loader **這個插件是必須的!**它的職責是將你定義過的其它規則複製並應用到 .vue 文件裏相應語言的塊。
        new VueLoaderPlugin
    ],
    resolve: { // 省略文件後綴時,默認按下面的配置取
        extensions: ['.js', '.vue'],
    },
    externals: { // 不把 vue 打包進去
        vue: 'vue',
    }
};
複製代碼

編寫插件

寫 vue 插件稍微複雜一點 😢,根據官網的案例,咱們須要提供一個包含 install 方法的對象或者一個函數(傳送門),供 Vue.use 調用註冊你的插件vue

  • 寫法一
import Component from './YanProgress.vue'; // 這個就是你平時寫的 SFC 組件

// 這裏要導出一個包含 install 方法的對象
let plugin = { // 這裏要導出一個 install 方法
    install(Vue,options) { 
        // 這裏寫你的代碼,你能夠全局註冊組件,也能夠寫全局指令,也能夠擴展 Vue 的方法
        // 1. 全局組件
        Vue.component('yan-progress',Component); 
        // 2. 全局方法或屬性
        Vue.myGlobalMethod = function () {
            // 邏輯...
        }
        // 3. 全局指令
        Vue.directive('my-directive', {
            bind (el, binding, vnode, oldVnode) {
                // 邏輯...
            }
        })
        // 4. 注入組件
        Vue.mixin({
            created: function () {
                // 邏輯...
            }
        })
        // 5. 添加實例方法
        Vue.prototype.$myMethod = function (methodOptions) {
            // 邏輯...
        }
    }
};

if (window && window.Vue) { // 若是是漸進式開發(script 引入簡單粗暴的開發方式),須要自動註冊你的插件
    window.Vue.use(plugin);
}

export default plugin;

複製代碼
  • 寫法二
import Component from './YanProgress.vue'; // 這個就是你平時寫的 SFC 組件

// 或者這裏也能夠寫成函數
function plugin(Vue,options) { 
        // 這裏寫你的代碼,你能夠全局註冊組件,也能夠寫全局指令,也能夠擴展 Vue 的方法
        Vue.component('yan-progress',Component); 
    }
};

if (window && window.Vue) { // 若是是漸進式開發(script 引入簡單粗暴的開發方式),須要自動註冊你的插件
    window.Vue.use(plugin);
}

export default plugin;
複製代碼

這樣寫的緣由是,下面源碼伺候😄node

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') { // 若是是帶有 install 方法的對象
      plugin.install.apply(plugin, args) // 不改變插件的 this(這裏的 this 仍是指向插件對象自己)
    } else if (typeof plugin === 'function') { // 若是是函數
      plugin.apply(null, args) // 不改變插件的 this(這裏應該是指向window,在瀏覽器非嚴格模式下)
    }
    installedPlugins.push(plugin)
    return this
  }
}
複製代碼

開源貢獻

擁抱開源,這樣才能讓社區,乃至行業發展更有動力,哎,似曾相識的趕腳,😂react

注:例如,你的 star 是對我最大的鼓勵,是支持我繼續開源的動力,😄webpack

  • awesome-vue 社區 awesome-vue
  • 其餘社區,能夠到 Github 探索

完結撒花🎉

👏 再次歡迎你們一塊兒和我搞 ji 由(Github)😊git

相關文章
相關標籤/搜索