1 vue.use()
/**
* Vue.use
* 做了两件事
* 定义 Vue.use,负责为 Vue 安装插件,做了以下两件事:
* 1、判断插件是否已经被安装,如果安装则直接结束
* 2、安装插件,执行插件的 install 方法
* @param {*} plugin install 方法 或者 包含 install 方法的对象
* @returns Vue 实例
*/
Vue.use = function(plugin:Function|Object){
// 获取Vue所有插件
const installPlugins= (this.installedPlugins || this._installedPlugins)
// 判断是否已经安装插件 如果安装过直接返回
if(installPlugins.includes(plugin)) return this
// 如果没安装过
// 将 Vue 构造函数放到第一个参数位置,然后将这些参数传递给 install 方法
const args = toArray(installPlugins,1)
args.unshift(this)
if (typeof plugin.install === 'function') {
// plugin 是一个对象,则执行其 install 方法安装插件
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
// 执行直接 plugin 方法安装插件
plugin.apply(null, args)
}
// 在 插件列表中 添加新安装的插件
installedPlugins.push(plugin)
return this
}
- Vue.mixin
/** * 定义 Vue.mixin,负责全局混入选项,影响之后所有创建的 Vue 实例,这些实例会合并全局混入的选项 * @param {*} mixin Vue 配置对象 * @returns 返回 Vue 实例 * mergeOptions 合并两个选项,出现相同配置项时,子选项会覆盖父选项的配置 */ Vue.mixin = function (mixin: Object) { // 在 Vue 的默认配置项上合并 mixin 对象 this.options = mergeOptions(this.options, mixin) return this }
4 Vue.set = set
/** * 通过 Vue.set 或者 this.$set 方法给 target 的指定 key 设置值 val * 如果 target 是对象,并且 key 原本不存在,则为新 key 设置响应式,然后执行依赖通知 */ export default set =function (target:Array|Object,key:any,val:any){ // 判断 taget 是否为空 if(!target){ console.warn('请输入target') } // 判断target 是否为数组 如果是数组根据下标通过splice 实现响应式 // 更新数组指定下标的元素,Vue.set(array, idx, val),通过 splice 方法实现响应式更新 // isValidArrayIndex(key)) 判断转换成数字 if(Array.isArray(target)&& isValidArrayIndex(key)){ // 获取最大值 target.length = Math.max(target.length,key) target.slice(key,1,val) return val } // 判断是否为对象 对象如果已有该属性直接更新 if(key in target && !(key in Object.prototype)){ target[key] = val return val } const ob = (target:any)._ob_ // 不能向 Vue 实例或者 $data 添加动态添加响应式属性,vmCount 的用处之一, // this.$data 的 ob.vmCount = 1,表示根组件,其它子组件的 vm.vmCount 都是 0 // target 不是响应式对象,新属性会被设置,但是不会做响应式处理 if (!ob) { target[key] = val return val } // 给对象定义新属性,通过 defineReactive 方法设置响应式,并触发依赖更新 defineReactive(ob.value, key, val) ob.dep.notify() return val }
nextTick
const callbacks = []
/**
* 完成两件事:
* 1、用 try catch 包装 flushSchedulerQueue 函数,然后将其放入 callbacks 数组
* 2、如果 pending 为 false,表示现在浏览器的任务队列中没有 flushCallbacks 函数
* 如果 pending 为 true,则表示浏览器的任务队列中已经被放入了 flushCallbacks 函数,
* 待执行 flushCallbacks 函数时,pending 会被再次置为 false,表示下一个 flushCallbacks 函数可以进入
* 浏览器的任务队列了
* pending 的作用:保证在同一时刻,浏览器的任务队列中只有一个 flushCallbacks 函数
* @param {*} cb 接收一个回调函数 => flushSchedulerQueue
* @param {*} ctx 上下文
* @returns
*/
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
// 用 callbacks 数组存储经过包装的 cb 函数
callbacks.push(()=>{
if(cb){
// 用try catch 包装回调函数 便于捕获错误
try{
cb.call(ctx)
} catch(e){
handleError(e,ctx,'nextTick')
}
} else if(_resolve){
_resolve(ctx)
}
})
if(!pending){
pending = true
// 执行 timerFunc,在浏览器的任务队列中(首选微任务队列)放入 flushCallbacks 函数
timerFunc()
}
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}