一文读懂Vue插件使用

  • 插件
  • 使用插件Vue.use()
  • 开发插件
  • Vue项目中应用
  • 配合require.context,动态导入全局组件
  • Vue项目中引入elementUi组件(全局)
  • 推荐阅读

插件

插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:

  • 添加全局方法或者 property。如:vue-custom-element
  • 添加全局资源:指令/过滤器/过渡等。如 vue-touch
  • 通过全局混入来添加一些组件选项。如 vue-router
  • 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。

一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

使用插件Vue.use()

通过全局方法 Vue.use()使用插件。它需要在你调用 new Vue() 启动应用之前完成

// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)

new Vue({
  // ...组件选项
})

也可以传入一个可选的选项对象

Vue.use(MyPlugin, { someOption: true })

Vue.use自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。

Vue.js 官方提供的一些插件 (例如vue-router) 在检测到 Vue 是可访问的全局变量时会自动调用 Vue.use()
然而在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use()

// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
var Vue = require('vue')
var VueRouter = require('vue-router')

// 不要忘了调用此方法
Vue.use(VueRouter)

awesome-vue 集合了大量由社区贡献的插件和库。

开发插件

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数Vue 构造器,第二个参数是一个可选的选项对象:

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}

Vue项目中应用

配合require.context,动态导入全局组件

目录结构如下

vuepress插件 vue使用插件_Vue


src\components\common\index.js

暴露install方法

export default {
  install(Vue) {
    const ctxRequire = require.context('@/components/common', false, /\.vue$/)
    debugger
    console.log('ctxRequire:', ctxRequire)
    // console.log('ctxRequire.resolve():', ctxRequire.resolve())
    console.log('ctxRequire.keys:', ctxRequire.keys())
    console.log('ctxRequire.id:', ctxRequire.id)
    ctxRequire.keys().forEach((filePath) => {
      const fileName = filePath.replace(/(.*\/)*([^.]+).vue$/ig, '$2') // 获取Vue组件文件名
      // "./breadcrumb.vue".replace(/(.*\/)*([^.]+).vue$/ig, '$2') 返回breadcrumb
      Vue.component(fileName, ctxRequire(filePath).default || ctxRequire(filePath))
    })
  }
}

打印如下

vuepress插件 vue使用插件_Vue插件_02


控制台点击ctxRequire打印的内容,会跳到源码页面,源码如下

var map = {
	"./VTitle.vue": "./src/components/common/VTitle.vue",
	"./breadcrumb.vue": "./src/components/common/breadcrumb.vue",
	"./common-title.vue": "./src/components/common/common-title.vue",
	"./custom-switch.vue": "./src/components/common/custom-switch.vue",
	"./file-list.vue": "./src/components/common/file-list.vue",
	"./more-button.vue": "./src/components/common/more-button.vue",
	"./nodata.vue": "./src/components/common/nodata.vue",
	"./pagination.vue": "./src/components/common/pagination.vue",
	"./previewDialog.vue": "./src/components/common/previewDialog.vue",
	"./server-type.vue": "./src/components/common/server-type.vue",
	"./step-nav.vue": "./src/components/common/step-nav.vue",
	"./svg-icon.vue": "./src/components/common/svg-icon.vue",
	"./tags.vue": "./src/components/common/tags.vue",
	"./upload-img.vue": "./src/components/common/upload-img.vue",
	"./upload-imgs.vue": "./src/components/common/upload-imgs.vue"
};


function webpackContext(req) {
	var id = webpackContextResolve(req);
	return __webpack_require__(id);
}
function webpackContextResolve(req) {
	if(!__webpack_require__.o(map, req)) {
		var e = new Error("Cannot find module '" + req + "'");
		e.code = 'MODULE_NOT_FOUND';
		throw e;
	}
	return map[req];
}
webpackContext.keys = function webpackContextKeys() {
	return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./src/components/common sync \\.vue$";

src\plugins\common.js

import Vue from 'vue'
import commonComps from '../components/common/index'

Vue.use(commonComps) // 会执行commonComps的install方法

src\main.js

import './plugins/common'
...

这样后,就可以在Vue任意地方用这些全局组件,不需要另外注册

PS:
ctxRequire(filePath).default || ctxRequire(filePath)相当于import进来的模块,假如filePath的值是"./breadcrumb.vue" 等同于
import breadcrumb from './breadcrumb.vue'

import breadcrumb from './breadcrumb.vue'

export default {
  install(Vue) {
    const ctxRequire = require.context('@/components/common', false, /\.vue$/)
    ctxRequire.keys().forEach((filePath) => {
      const fileName = filePath.replace(/(.*\/)*([^.]+).vue$/ig, '$2') // 获取Vue组件文件名
      if (fileName === 'breadcrumb') {
        console.log('breadcrumb:', breadcrumb)
        console.log(ctxRequire(filePath).default || ctxRequire(filePath))
        console.log(breadcrumb === (ctxRequire(filePath).default || ctxRequire(filePath))) // true
      }
      console.log('ctxRequire(filePath):', ctxRequire(filePath))
      Vue.component(fileName, ctxRequire(filePath).default || ctxRequire(filePath))
    })
  }
}

打印如下

vuepress插件 vue使用插件_vue_03

Vue项目中引入elementUi组件(全局)

src\plugins\element-ui.js

import Vue from 'vue'
// https://element.eleme.cn/#/zh-CN/component/quickstart
import {
  Input,
  Button,
  Form,
  FormItem,
  Cascader,
  Dialog,
  Menu,
  MenuItem,
  MenuItemGroup,
  Submenu,
  Upload,
  Breadcrumb,
  BreadcrumbItem,
  Dropdown,
  DropdownMenu,
  DropdownItem,
  DatePicker,
  Message,
  MessageBox,
  Notification,
  Badge,
  Popover,
  Select,
  Option,
  Carousel,
  CarouselItem,
  Loading,
  Radio,
  RadioGroup,
  RadioButton,
  Table,
  TableColumn,
  Pagination,
  Row,
  Col,
  Card,
  Switch,
  Image,
  InfiniteScroll,
  Alert,
  Tooltip,
  Divider,
  Tree,
  Checkbox,
  CheckboxGroup,
  Step,
  Steps,
  Tabs,
  TabPane
} from 'element-ui'

Vue.prototype.$ELEMENT = { size: 'small' }

Vue.use(Divider)
Vue.use(Input)
Vue.use(Button)
Vue.use(Cascader)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Dropdown)
Vue.use(DropdownMenu)
Vue.use(DropdownItem)
Vue.use(Dialog)
Vue.use(Menu)
Vue.use(MenuItem)
Vue.use(Submenu)
Vue.use(MenuItemGroup)
Vue.use(Upload)
Vue.use(Breadcrumb)
Vue.use(BreadcrumbItem)
Vue.use(DatePicker)
Vue.use(Badge)
Vue.use(Popover)
Vue.use(Select)
Vue.use(Option)
Vue.use(Carousel)
Vue.use(CarouselItem)
Vue.use(Radio)
Vue.use(RadioGroup)
Vue.use(RadioButton)
Vue.use(Table)
Vue.use(TableColumn)
Vue.use(Pagination)
Vue.use(Row)
Vue.use(Col)
Vue.use(Card)
Vue.use(Switch)
Vue.use(Image)
Vue.use(Alert)
Vue.use(Tooltip)
Vue.use(Tree)
Vue.use(Checkbox)
Vue.use(CheckboxGroup)
Vue.use(InfiniteScroll)
Vue.use(Loading.directive)
Vue.use(Step)
Vue.use(Steps)
Vue.use(Tabs)
Vue.use(TabPane)
Vue.prototype.$message = Message
Vue.prototype.$notify  = Notification
Vue.prototype.$confirm = MessageBox.confirm

src\main.js 引入该文件

// ...
import './plugins/element-ui'

启动项目后 就可以直接在Vue组件里使用element组件了