1、Vue插件的功能
- 添加全局方法或者属性,例如vue-custom-element;
- 添加全局资源:指令/过滤器或者过渡等;
- 通过全局混入来添加一些组件选项,例如vue-router;
- 添加vue实例方法,将其加到原型上;
- 一个组件库,提供自己的API,同时提供上面提到的一个或者多个功能,例如Element-ui提供自己的API;
2、Vue的钩子函数
- 源码中(/src/core/instance/index.js),Vue是一个构造函数,所以我们需要使用new的方式创建一个关于Vue的实例,如果是生产环境或者不是Vue的实例,将发出警告,然后通过Vue实例上的_init()方法进行Vue的初始化;
function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) }
- _init()方法是Vue通过prototype来实现的一个原型属性,Vue先调用了initLifecycle(vm)、initEvents(vm)、initRender(vm)这三个方法,用于初始化生命周期、事件和渲染函数,且发生在beforeCreated钩子函数之前,在Vue中几乎所有的钩子(
errorCaptured
除外)函数执行都是通过callHook(vm: Component, hook: string) 来调用的;Vue.prototype._init = function (options?: Object) { ... // expose real self vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created') ... if (vm.$options.el) { vm.$mount(vm.$options.el) } }
- callHook()方法根据传入的hook从实例中拿到对应的回调函数数组(/packages/vue-template-compiler/browser.js下的 LIFECYCLE_HOOKS),然后再执行,步骤如下:
- 把所有同类钩子先合并成数组(一个实例通过mixins可能有很多个相同钩子),然后存放在 vm.$options,类似于mixin,然后遍历执行;
- 使用
//callHook的作用就是执行用户自定义的钩子函数,并将钩子中this指向指为当前的组件实例 export function callHook(vm:Component, hook:String) { //vm为当前vue实例,hook为钩子函数名称 pushTarget(); //为了避免在某些生命周期钩子中使用 props 数据导致收集冗余的依赖 //获取对相应的钩子函数内容 var handlers = vm.$options[hook]; if (handlers) { for (var i = 0, j = handlers.length; i < j; i++) { try { // 直接调用 handlers[i].call(vm); } catch (e) { handleError(e, vm, (hook + " hook")); } } } // 钩子函数事件emit if (vm._hasHookEvent) { vm.$emit('hook:' + hook); } popTarget();//为了避免在某些生命周期钩子中使用 props 数据导致收集冗余的依赖 }
3、插件的开发流程
- 如果插件是一个对象,必须暴露一个install方法,如果是一个函数,自己则会被作为install方法
Myplugin.install = (Vue,options) => { //添加全局方法或者属性 Vue.globalMethod = () => {} //添加全局资源 Vue.directive(directiveName,{}) //注入组件选项 Vue.mixin({}) //添加实例方法 Vue.prototype.commonMethod = () => {}
注意:首先根据installed属性来判断插件是否被注册,防止二次注册,然后利用Vue.mixin使插件在beforeCreate(即组件实例化之前)注册,在destoryed中销毁组件,最后利用defineProperty;让复制关系为已读,且不会被人为修改,结尾还是用Vue.component方法注册router-view与router-link两个组件;
- 在new Vue()(即组件实例化之前)使用全局方法Vue.use(),执行时自动执行install方法,用来安装插件,多次调用,只会注册一次;
注意:Vue上定义use方法,参数可以是Object或者Function,逻辑:先判断插件是否注册过,防止重复注册,然后使用工具类的方法toArray拿到use中从1-剩余的参数,最后根据是 Object或者Function执行对应的install方法,并记录该组件已经被注册过(将参数放入一个数组中)。
4、遇到的问题
暂无