浅谈vue.use()方法从源码到使用


Posted in Javascript onMay 12, 2019

关于 vue.use 我们都知道些什么?

在做 vue 开发的时候大家一定经常接触 Vue.use() 方法,官网给出的解释是: 通过全局方法 Vue.use() 使用插件;我觉得把使用理解成注册更合适一些,首先看下面常见的注册场景。

import Router from 'vue-router'
Vue.use(Router)

import Vuex from 'vuex'
Vue.use(Vuex)

import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts

关于 echarts 的注册很简单,直接挂在 Vue 方法的原型上,通过原型链继承的关系可以在任意一个组件里通过 this.$echarts 访问到 echarts 实例,我们来写一个简单的例子证明一下。

function myVue(title){
 this.title = title
}
myVue.prototype.myUse = '在原型上添加公共属性'
const A = new myVue('我是实例A')
const B = new myVue('我是实例B')
console.log(A.title, B.title, A.myVue, B.myVue, )
// 我是实例A 我是实例B 在原型上添加公共属性 在原型上添加公共属性

而 Router 和 Vuex 的注册就要去分析 Vue.use() 的源码了,在分析源码之前先总结一下官方对 Vue.use() 方法的说明:

  • 通过全局方法 Vue.use() 使用插件
  • Vue.use 会自动阻止多次注册相同插件
  • 它需要在你调用 new Vue() 启动应用之前完成
  • Vue.use() 方法至少传入一个参数,该参数类型必须是 Object 或 Function,如果是 Object 那么这个 Object 需要定义一个 install 方法,如果是 Function 那么这个函数就被当做 install 方法。在 Vue.use() 执行时 install 会默认执行,当 install 执行时第一个参数就是 Vue,其他参数是 Vue.use() 执行时传入的其他参数。

官网说 Vue.use() 是用来使用插件的,那么传入的 Router 和 Vuex 就是这里指的插件,而这个插件本质上又是一个 install 方法。至于 install 方法内部实现了什么逻辑就由插件自身的业务决定了。

源码分析

首先说一下 Flow,vue源码中那些奇怪的写法 Vue.use = function (plugin: Function | Object) 是 Flow 的语法,Flow 是 facebook 出品的 JavaScript 静态类型检查工具。JavaScript 是动态类型语言,它的灵活性有目共睹,但是过于灵活的副作用是很容易就写出非常隐蔽的隐患代码,在编译期甚至看上去都不会报错,但在运行阶段就可能出现各种奇怪的 bug。

下面我们正式开始分析源码,Vue.use() 的源码很简单30行都不到,首先看 src/core/global-api/use.js 下 Vue.use() 方法的定义:

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 this
  }
  const args = toArray(arguments, 1)
  args.unshift(this)
  if (typeof plugin.install === 'function') {
   plugin.install.apply(plugin, args)
  } else if (typeof plugin === 'function') {
   plugin.apply(null, args)
  }
  installedPlugins.push(plugin)
  return this
 }
}

上面源码中使用了工具函数 toArray ,该函数定义在 src/shared/util.js

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.use = function (plugin: Function | Object) {

在全局api Vue 上定义了 use 方法,接收一个 plugin 参数可以是 Function 也可以是 Object,这就和前面官方规定的 Vue.use() 第一个参数要求的类型对应上了。

if (installedPlugins.indexOf(plugin) > -1) {

用来判断该插件是不是已经注册过,防止重复注册。

const args = toArray(arguments, 1)

arguments是 Vue.use() 方法的参数列表是一个类数组,后面的 1 先理解成一个常量,toArray 方法的作用就是把第一个 Array 参数从下标为1截取到最后。也就拿到了 Vue.use() 方法除去第一个之外的其他参数,这些参数准备在调用 instll 方法的时候传入。

if (typeof plugin.install === 'function') {
} else if (typeof plugin === 'function') {

这里的if语句是判断 Vue.use() 传入的第一个参数是 Object 还是 Function。

plugin.install.apply(plugin, args)
plugin.apply(null, args)

判断完之后执行那个对应的 install 方法,用 apply 改变 this 指向,并把 toArray 得到的剩余参数传入。

installedPlugins.push(plugin)

最后记录该组件已经注册过了

现在我们发现 Vue.use() 的注册本质上就是执行了一个 install 方法,install 里的内容由开发者自己定义,通俗讲就是一个钩子可能更贴近语义化而已。

Vue.use()有什么用

在 install 里我们可以拿到 Vue 那么和 Vue 相关的周边工作都可以考虑放在 Vue.use() 方法里,比如:

  • directive注册
  • mixin注册
  • filters注册
  • components注册
  • prototype挂载
  • ...

echarts 用 Vue.use() 来注册

main.js

import Vue from 'vue'
import echarts from './echarts.js'
Vue.use(echarts)

new Vue({
 ...
})

echarts.js

import Echarts from 'echarts'
export default {
 install(Vue){
  Vue.prototype.$echarts = Echarts
 }
}

这样写的好处是可以在 install 的文件里做更多配置相关的工作,main.js 不会变的臃肿,更方便管理。

全局组件用 Vue.use() 来注册

base.js

import a from './a'
import b from './b'
let components = { a, b }
const installBase = {
 install (Vue) {
  Object.keys(components).map(key => Vue.component(key, components[key]))
 }
}

main.js

import Vue from 'vue'
import base from './base.js'
Vue.use(base)

new Vue({
 ...
})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
纯css+js写的一个简单的tab标签页带样式
Jan 28 Javascript
修复bash漏洞的shell脚本分享
Dec 31 Javascript
浅谈jQuery中replace()方法
May 13 Javascript
JS实现新浪微博效果带遮罩层的弹出框代码
Oct 12 Javascript
分享两款带遮罩的jQuery弹出框
Dec 30 Javascript
Bootstrap按钮功能之查询按钮和重置按钮
Oct 26 Javascript
jQuery Validate 无法验证 chosen-select元素的解决方法
May 17 jQuery
微信小程序实现列表下拉刷新上拉加载
Jul 29 Javascript
Vue 项目代理设置的优化
Apr 17 Javascript
Vue数据绑定实例写法
Aug 06 Javascript
es6数组的flat(),flatMap()函数用法实例分析
Apr 18 Javascript
Vue 封装防刷新考试倒计时组件的实现
Jun 05 Javascript
Vue安装浏览器开发工具的步骤详解
May 12 #Javascript
微信小程序缓存过期时间的使用详情
May 12 #Javascript
从0到1搭建element后台框架优化篇(打包优化)
May 12 #Javascript
Vue项目服务器部署之子目录部署方法
May 12 #Javascript
vue配置接口域名方法总结
May 12 #Javascript
详解babel升级到7.X采坑总结
May 12 #Javascript
babel7.x和webpack4.x配置vue项目的方法步骤
May 12 #Javascript
You might like
分享最受欢迎的5款PHP框架
2014/11/27 PHP
php上传图片客户端和服务器端实现方法
2015/03/30 PHP
[原创]ThinkPHP让../Public在模板不解析(直接输出)的方法
2015/10/09 PHP
PHP使用pdo实现事务处理操作示例
2018/09/05 PHP
javascript实现的像java、c#之类的sleep暂停的函数代码
2010/03/04 Javascript
js时间日期格式化封装函数
2014/12/02 Javascript
AngularJS基础知识笔记之过滤器
2015/05/10 Javascript
JS查找字符串中出现次数最多的字符
2016/09/05 Javascript
微信小程序技巧之show内容展示,上传文件编码问题
2017/01/23 Javascript
搭建简单的nodejs http服务器详解
2017/03/09 NodeJs
VUE2.0中Jsonp的使用方法
2018/05/22 Javascript
微信小程序API—获取定位的详解
2019/04/30 Javascript
JavaScript实现轮播图片完整代码
2020/03/07 Javascript
vue+高德地图实现地图搜索及点击定位操作
2020/09/09 Javascript
在vs code 中如何创建一个自己的 Vue 模板代码
2020/11/10 Javascript
[01:10]3.19DOTA2发布会 三代刀塔人第一代
2014/03/25 DOTA
[01:53]3.19 DOTA2发布会 现场精彩Coser表演
2014/03/25 DOTA
[13:55]Newbee vs Team Spirit
2018/06/07 DOTA
[01:02:09]Liquid vs TNC 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21
2020/07/19 DOTA
python根据时间生成mongodb的ObjectId的方法
2015/03/13 Python
在Django的模型和公用函数中使用惰性翻译对象
2015/07/27 Python
Python3的urllib.parse常用函数小结(urlencode,quote,quote_plus,unquote,unquote_plus等)
2016/09/18 Python
python 字典中文key处理,读取,比较方法
2018/07/06 Python
Python如何优雅获取本机IP方法
2019/11/10 Python
Python xlrd/xlwt 创建excel文件及常用操作
2020/09/24 Python
CSS3截取字符串实例代码【推荐】
2018/06/07 HTML / CSS
突袭HTML5之Javascript API扩展4—拖拽(Drag/Drop)概述
2013/01/31 HTML / CSS
会计岗位职责模板
2014/03/12 职场文书
春风行动实施方案
2014/03/28 职场文书
美食节策划方案
2014/05/26 职场文书
2015年教师节感恩寄语
2015/03/23 职场文书
自主招生推荐信怎么写
2015/03/26 职场文书
上课迟到检讨书
2015/05/06 职场文书
2016年领导干部廉政承诺书
2016/03/24 职场文书
什么是执行力?9个故事告诉您:成功绝非偶然!
2019/07/05 职场文书
HTML5页面音频自动播放的实现方式
2021/06/21 HTML / CSS