vue.use()是全局注册一个组件或者插件的方法. 每次注册前, 都会判断一下这个组件或者插件 (plugins) 是否注册过, 如果注册过, 就不会再次注册了.
我们在使用 Vue 做项目开发的时候, 看到不少轮子都是通过 Vue.use 来进行使用, 感觉甚是高大上.
不过 Vue.use 到底是什么鬼? 不妨来看个究竟.
其实这些轮子都可以称之为插件, 它的功能范围没有严格的限制, 一般包含如下几种:
添加全局方法或者属性. 如: vue-custom-element
添加全局资源: 指令 / 过滤器 / 过渡 / 组件等. 如 vue-touch
通过全局混入来添加一些组件选项. 如 vue-router
添加 Vue 实例方法, 通过把它们添加到 Vue.prototype 上实现.
一个库, 提供自己的 API, 同时提供上面提到的一个或多个功能. 如 vue-router
无论大小, 插件要实现的功能无非就是上述这几种. 但是, 这并不妨碍我们创造出复杂的插件, 不过我们还是希望给用户提供一个简单的使用方法, 他不需要关注插件内部做了些什么. 固 Vue 提供了 use 方法, 专门来在 new Vue()之前使用插件.
不管是官方提供的插件 (例如 vue-router,vuex), 还是第三方的插件(例如 ElementUI,ant) 都是采用了此方式, 不外乎插件内部的功能不同而已. 当然, 还有其他诸多此类插件, awesome-vue 就集合了大量由社区贡献的插件和库.
接下来, 我们就来看下这个神秘的 use 方法是如何实现的.
vue.js 的插件应该暴露一个 install 方法. 这个方法的第一个参数是 Vue 构造器, 第二个参数是一个可选的选项对象, 用于传入插件的配置:
- MyPlugin.install = function (Vue, options) {
- // 1. 添加全局方法或属性
- Vue.myGlobalMethod = function () {
- // 逻辑...
- }
- // 2. 添加全局资源
- Vue.directive('my-directive', {
- bind (el, binding, vnode, oldVnode) {
- // 逻辑...
- }
- ...
- })
- // 3. 注入组件选项
- Vue.mixin({
- created: function () {
- // 逻辑...
- }
- ...
- })
- // 4. 添加实例方法
- Vue.prototype.$myMethod = function (methodOptions) {
- // 逻辑...
- }
- // 5. 注册全局组件
- Vue.component('myButton',{
- // ... 组件选项
- })
- }
- Vue.use(MyPlugin,{
- // ...options
- })
一个插件内部大概就是如上所示, 其实也不外乎上述那几种东西, 甚是简单. 接下来我们就来看下真实的案例 ElementUI:
- const components = [ Pagination, Dialog, Autocomplete/* 此处由于篇幅省略若干个组件 */];
- const install = function(Vue, opts = {}) {
- locale.use(opts.locale);
- locale.I18N(opts.I18N);
- // 注册全局组件
- components.forEach(component => {
- Vue.component(component.name, component);
- });
- Vue.use(InfiniteScroll);
- Vue.use(Loading.directive);
- // 添加实例方法
- Vue.prototype.$ELEMENT = {
- size: opts.size || '',
- zIndex: opts.zIndex || 2000
- };
- // 添加实例方法
- Vue.prototype.$loading = Loading.service;
- Vue.prototype.$msgbox = MessageBox;
- Vue.prototype.$alert = MessageBox.alert;
- Vue.prototype.$confirm = MessageBox.confirm;
- Vue.prototype.$prompt = MessageBox.prompt;
- Vue.prototype.$notify = Notification;
- Vue.prototype.$message = Message;
- };
- /* istanbul ignore if */
- if (typeof Windows !== 'undefined' && Windows.Vue) {
- install(Windows.Vue);
- }
- export default {
- version: '2.13.0',
- locale: locale.use,
- I18N: locale.I18N,
- install,
- CollapseTransition,
- Loading,
- Pagination,
- Dialog,
- Autocomplete,
- // ...other components
- };
我们不难发现, 其实自己来实现一个插件也是超级简单, 只要对外暴露一个 install 方法即可, 在使用 Vue.use 的时候, 会调用这个方法. 所以我们只要将要实现的内容放到 install 内部即可. 这样的好处就是插件需要一开始调用的方法都封装在 install 里面, 更加精简和可拓展性更高.
大家可能也有注意到, 这里的 install 其实是将所有的组件全部引入了. 作为一个庞大的插件库, 这样可能会有一些性能问题. 用过的 ElementUI 的同学都知道, 它是支持按需引入的, 其实在上面的示例中也可以发现一些蛛丝马迹.
- const components = [ Pagination, Dialog, Autocomplete/* 此处由于篇幅省略若干个组件 */];
- // .... 省去中间内容
- export default {
- version: '2.13.0',
- locale: locale.use,
- I18N: locale.I18N,
- install,
- CollapseTransition,
- Loading,
- Pagination,
- Dialog,
- Autocomplete,
- // ...other components
- };
这里将每个组件都单独都导出了, 而在每个组件内部, 也类似的暴露了 install 来组件每个组件, 这样就可以单独 Vue.use 每个组件, 从而实现按需引入的目的.
- import Alert from './src/main';
- /* istanbul ignore next */
- Alert.install = function(Vue) {
- Vue.component(Alert.name, Alert);
- };
- export default Alert;
除了上述内容之外, 还有几点值得我们注意一下:
插件传入的如果是一个对象, 则执行其 install 方法, 如果是一个函数, 则执行它自身, 并 bind this 为 null, 然后传入额外的参数
- if (typeof plugin.install === 'function') {
- plugin.install.apply(plugin, args);
- } else if (typeof plugin === 'function') {
- plugin.apply(null, args);
- }
如果插件没有被注册过, 那么注册成功之后会给插件添加一个 installed 的属性, 其值为 true.Vue.use 方法内部会检测插件的 installed 属性, 从而避免重复注册插件
Vue.use 其实并不神秘, 内部还是我们平时使用的这些东西, 仅仅只是给他们套上了一层高端的外衣而已. 我们在开发中, 也可以尝试使用这种方式, 不仅简单, 而且有逼格
更多前端开发 https://www.html.cn/ 知识, 请查阅 HTML 中文网 !!
来源: http://www.css88.com/qa/vue-js/17125.html