从vue.use引发的vue.component和vue.extend一系列连锁思考

前言:在写全局组件的时候,我们会用到vue.component和vue.use。那他们到底有啥区别,和内在的联系呢。


vue.use的源码实现

上来先举个例子,我们经常在引用第三方插件的时候会看到再main.js文件中这样写:
从vue.use引发的vue.component和vue.extend一系列连锁思考_第1张图片
那么vue.use具体做了一些什么呢,我们翻开vue的源码一探究竟(源码文件):

import { toArray } from '../util/index'

export function initUse (Vue: GlobalAPI) {
 Vue.use = function (plugin: Function | Object) {
// 限制了自定义组建的类型
   const installedPlugins = (this._installedPlugins || (this._installedPlugins =
[]))
//保存注册组件的数组,不存在及创建
   if (installedPlugins.indexOf(plugin) > -1) {
//判断该组件是否注册过,存在return Vue对象
     return this
   }
//调用`toArray`方法
   const args = toArray(arguments, 1)
   args.unshift(this)
//将Vue对象拼接到数组头部
   if (typeof plugin.install === 'function') {
//如果组件是对象,且提供install方法,调用install方法将参数数组传入,改变`this`指针为该组件
     plugin.install.apply(plugin, args)
   } else if (typeof plugin === 'function') {
//如果传入组件是函数,这直接调用,但是此时的`this`指针只想为`null` 
     plugin.apply(null, args)
   }
//在保存注册组件的数组中添加
   installedPlugins.push(plugin)
   return this
 }
}

①:Vue.use接受一个参数plugin,方法检测了installedPlugins这个数组中是否已经包含想要注册的组件,可知插件只允许被注册一次,二次注册是无效直接返回this。
②:调用toArray将转入的参数转换成数组,toArray源码如下:

export function toArray (list: any, start?: number): Array<any> {
  start = start || 0
  let i = list.length - start
//将存放参数的数组转为数组,并除去第一个参数(该组件)
  const ret: Array<any> = new Array(i)
//循环拿出数组
  while (i--) {
    ret[i] = list[i + start]
  }
  return ret
}

③:把当前Vue对象this插入转化后的数组前
④:判断plugin中install是否是一个方法,如果是,则传入plugin及转化后的数组;此外,如果plugin本身就是一个方法,则传入转化后的数组,随后执行这个方法,由此可知Vue.use(插件)实际上会调用插件的install方法,并且调用use的时候是可以传参数的。
注:以上还可以知道,vue只会对plugin中的两种情况处理,即要么plugin中有install函数,要么plugin本身就是一个函数。
⑤:将注册后的插件推进installedPlugins,避免重复注册,返回当前实例,代码执行结束。


利用vue.use原理实现批量注册全局组件

根据上面的分析我们可以利用vue.use自己写一个批量组册全局组件的方案
1、在src下的common文件下新建component文件夹用来存放我们的公用全局组件。如下图:
从vue.use引发的vue.component和vue.extend一系列连锁思考_第2张图片
2、在index.js文件中倒入所有的组件,并封装成install 方法导出。如下:

import boxShow from './boxShow'
import boxTip from './boxTip'

const commontCop = { // 导出一个对象,并且给对象里添加install属性方法
  install(vue) { // 这形式参数vue 在vue.use方法被掉用的时候传入vue的实例对象
    vue.component('boxShow', boxShow)
    vue.component('boxTip', boxTip)
  }
}
export default commontCop
  • 导出一个对象,并且给对象里添加install属性方法
  • 这里的式参数vue 在vue.use方法被掉用的时候传入vue的实例对象,就是上面源码分析中的这一段: plugin.install.apply(plugin, args) 。args中的第一个参数就是unshift进去的vue的实例对象

3、在main.js中直接使用vue.use注册成为全局组件。如下:
从vue.use引发的vue.component和vue.extend一系列连锁思考_第3张图片
4. 这样注册好,就可以全局愉快的使用了哦哦。像这样调用:
从vue.use引发的vue.component和vue.extend一系列连锁思考_第4张图片
注意:我们也可以在main.js中直接使用vue.component方法注册组件,可以参考以前写的文章项目实战之vue爬坑之路:vue框架中如何注册全局公共过滤器filter、全局公共插件、全局公共组件component
这个方法有个缺点就是这能一个一个注册,也就是说如果要注册多个全局组件,你只能在main.js中写多个vue.component方法

进阶一步,利用require.context实现批量自动注册

所谓批量自动注册就是在批量注册的基础上加上自动注册,也就是以后我们写全局组件的时候只管往指定的目录下添加.vue文件就行了,其他的注册导入的工作交给require.context来完成

我们只需要将上面的index文件修改如下:

const files = require.context('../component', false, /\.vue$/)
const fileNames = files.keys() // 获取文件夹下面的所有.vue文件的文件相对路径
const fileModule = []
fileNames.forEach(fileName => {
  // const tempName = fileName.replace(/^\.\/(.*)\.\w+$/, '$1') // 将文件名剥离出来
  const tempModule = files(fileName).default // 获取倒入的文件对象(也就是我们用import导入的内容)
  let tempObj = {
    name: tempModule.name,
    module: tempModule
  }
  fileModule.push(tempObj)
});
const commontCop = {
  install(vue) {
    fileModule.forEach(item => vue.component(item.name, item.module))
  }
}
export default commontCop

这里我们需要自行学习一波require.context的使用,官方链接详细说明

vue.component的源码实现分析

(待续。。。。)

你可能感兴趣的:(vue)