编写 Vue 插件

插件是封装在 .js 文件中的全局 JavaScript 函数,可通过 Vue.use 全局方法安装到应用中。在前文第 4 章《添加视图、路由和过渡效果》的示例中,我们已经使用过 vue-routervue-metaVue 插件。这些插件必须在通过 new 实例化根 Vue 之前完成安装,如下例所示:

// src/entry.js
import Vue from 'vue'
import Meta from 'vue-meta'

Vue.use(Meta) // 插件安装必须放在Vue实例化之前
new VueRouter({ ... })

通过 Vue.use 可以传入配置参数,语法格式为:

Vue.use(<plugin>, <options>)

例如,为 vue-meta 插件配置参数:

Vue.use(Meta, {
  keyName: 'metaData',    // 默认值: 'metaInfo'
  refreshOnceOnNavigation: true // 默认值: false
})

配置参数是可选的,这意味着可以不传参直接使用插件。Vue.use 还具有以下特性:

  • 自动防止重复安装(多次调用仅生效一次)

  • 支持可选配置参数

您可以通过 awesome-vue 获取海量 社区 贡献的插件和库资源。

接下来我们将具体探讨如何创建自定义 Vue 插件。

在 Vue 中编写自定义插件

编写 Vue 插件相当简单,只需在插件中使用 install 方法,该方法接收 Vue 作为第一个参数,options 作为第二个参数:

// plugin.js
export default {
  install(Vue, options) {
    // ...
  }
}

让我们为一个标准的 Vue 应用创建一个简单的自定义问候插件,支持不同的语言。语言可以通过 options 参数进行配置;当没有提供选项时,将使用英语作为默认语言:

  1. /src/ 目录下创建 /plugins/ 文件夹,并在其中创建 basic.js 文件,代码如下:

    // src/plugins/basic.js
    export default {
      install(Vue, options) {
        if (options === undefined) {
          options = {}
        }
        let { language } = options
        let languages = {
          'EN': 'Hello!',
          'ES': 'Hola!'
        }
        if (language === undefined) {
          language = 'EN'
        }
        Vue.prototype.$greet = (name) => {
          return languages[language] + ' ' + name
        }
        Vue.prototype.$message = 'Helló Világ!'
      }
    }

    在这个简单插件中,我们还添加了一个名为 $message 的实例属性,默认值为匈牙利语的 "Hello World!"(Helló Világ!),该属性可以在组件中使用时被修改。注意 { language } = options 是 ES6 的写法,等同于 language = options.language。此外,方法和属性应添加 $ 前缀,这是约定俗成的做法。

  2. 安装并配置该插件:

    // src/entry.js
    import PluginSample from './plugins/basic'
    Vue.use(PluginBasic, {
      language: 'ES'
    })
  3. 然后就可以在任何 Vue 组件中全局使用该插件,例如:

    // src/components/home.vue
    <p>{{ $greet('John') }}</p>
    <p>{{ $message }}</p>
    <p>{{ messages }}</p>
    
    export default {
      data() {
        let helloWorld = []
        helloWorld.push(this.$message)
    
        this.$message = 'Ciao mondo!'
        helloWorld.push(this.$message)
    
        return { messages: helloWorld }
      }
    }

当你在浏览器中运行应用时,屏幕上会显示以下输出:

Hola! John
Ciao mondo!
[ "Helló Világ!", "Ciao mondo!" ]

你也可以在插件中使用组件(component)或指令(directive),例如:

// src/plugins/component.js
export default {
  install(Vue, options) {
    Vue.component('custom-component', {
      // ...
    })
  }
}

// src/plugins/directive.js
export default {
  install(Vue, options) {
    Vue.directive('custom-directive', {
      bind(el, binding, vnode, oldVnode) {
        // ...
      }
    })
  }
}

我们还可以使用 Vue.mixin() 将插件注入到所有组件中:

// src/plugins/plugin-mixin.js
export default {
  install(Vue, options) {
    Vue.mixin({
      // ...
    })
  }
}

你可以在我们的 GitHub 仓库的 /chapter-6/vue/webpack/ 目录中找到上述示例 Vue 应用。

就是这样。创建一个可以安装并在 Vue 应用中使用的插件相当简单,不是吗?那么在 Nuxt 应用中呢?我们如何在 Nuxt 应用中安装上述自定义 Vue 插件?让我们在下一节中一探究竟。

将 Vue 插件导入到 Nuxt 中

Nuxt 应用中,插件的运行机制与 Vue 应用基本相同。所有插件都必须在根 Vue 实例初始化之前完成加载。若需使用前文示例中的 Vue 插件,我们需要按照以下步骤进行配置:

  1. 插件导入配置

    将自定义的 basic.js 插件复制到 Nuxt 项目的 /plugins/ 目录后,创建导入文件:

    // plugins/basic-import.js
    import Vue from 'vue'
    import PluginSample from './basic'
    Vue.use(PluginSample) // 本次安装未传入配置参数

    这次我们在使用 Vue.use 方法安装插件时跳过了 options

  2. Nuxt 配置文件 plugins 选项注册

    在配置文件中声明插件路径:

    export default {
      plugins: [
        '~/plugins/basic-import'
      ]
    }
  3. 页面组件调用

    任意页面均可调用插件功能:

    // pages/index.vue
    <p>{{ $greet('Jane') }}</p>
    <p>{{ $message }}</p>
    <p>{{ messages }}</p>
    
    export default {
      data() {
        let helloWorld = []
        helloWorld.push(this.$message) // 初始值 "Helló Világ!"
        this.$message = 'Olá Mundo!'  // 修改为葡萄牙语
        helloWorld.push(this.$message)
        return { messages: helloWorld }
      }
    }
  4. 运行效果

    浏览器将显示:

    Hello! Jane
    Olá Mundo!
    [ "Helló Világ!", "Olá Mundo!" ]

本次示例中,$greet 方法输出英文问候语 "Hello!" 是因为安装插件时未设置语言参数。需要注意的是:

  • 仅在首页模板中通过 this.$message = 'Olá Mundo!' 设置了葡萄牙语版本

  • 其他页面(如 /about/contact)仍会显示原始的匈牙利语 "Helló Világ!"

正如本章开头所述,虽然社区提供了大量实用的 Vue 插件,但部分插件由于不支持服务端渲染(SSR),可能仅能在浏览器环境下运行。下一节我们将专门探讨这类插件的解决方案。

导入不支持 SSR 的外部 Vue 插件

Nuxt 中,部分 Vue 插件已预装完毕,例如:

  • vue-router

  • vue-meta

  • vuex

  • vue-server-renderer

对于未预装的插件,可参照前文安装自定义插件的步骤进行配置。以下以 vue-notifications 插件为例:

  1. 通过 npm 安装插件

    $ npm i vue-notification
  2. 创建插件导入文件

    // plugins/vue-notifications.js
    import Vue from 'vue'
    import VueNotifications from 'vue-notifications'
    Vue.use(VueNotifications)
  3. 配置 nuxt.config.js

    // nuxt.config.js
    export default {
      plugins: ['~/plugins/vue-notifications']
    }

仅客户端运行配置

对于不支持 SSR 或只需在客户端运行的插件,可通过 mode: 'client' 参数确保不在服务端执行:

// nuxt.config.js
export default {
  plugins: [
    { src: '~/plugins/vue-notifications', mode: 'client' }
  ]
}

正如你所见,安装一个 Vue 插件只需要三个步骤,无论是外部插件还是你自定义的插件。简而言之,Vue 插件是全局 JavaScript 函数,通过使用 Vue.use 方法注入到 Vue 实例中,并在插件内部暴露一个 install 方法。

但是,在 Nuxt 本身中,还有其他创建全局函数的方法,这些函数可以注入到 Nuxt 上下文(context)和 Vue 实例($root)中,而无需使用 install 方法。我们将在接下来的章节中探讨这些方法。

更多关于 vue-notifications 的信息,请访问: https://github.com/euvl/vue-notification