Vue源码02-静态方法和mergeOptions

通过上节我们对Vue的流程有了一个大概的了解,这节我们将进一步分析

Vue的静态方法

Vue.use

在我们写Vue项目的时候,应该都会用到这个东西,它的作用只有一个就是给我项目注册插件

  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
  }
  • 注册插件的时候,我们会存一个数组,用来判断是否已经存储了
  • 如果插件有install方法我们把Vue当成第一个参数传给插件,并调用install方法
  • 没有install,它本事是一个function,我们直接调用
Vue.mixin

不推荐在应用代码中使用

 Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
  • 全局注册一个混入,影响注册之后所有创建的每个 Vue 实例
Vue.extend

使用基础 Vue 构造器,创建一个“子类”。

Vue.extend = function (extendOptions) {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }
    const Sub = function VueComponent (options) {
      this._init(options)
    }
    .....
   cachedCtors[SuperId] = Sub
    return Sub
  }
  • 判断extendOptions_ _Ctor[SuperId]是否存在,存在直接拿去
  • 生成Sub函数,
  • 对Sub的options以及方法初始化(具体可以查看源码,比较简单)
  • 返回Sub
Vue.component(),Vue.directive(),Vue.filter()
  ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id, definition
    ) {
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })

这里可以去看看官网对这几个静态方法的案例讲解,你就会非常清楚了

Vue.prototype._init

mergeOptions
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  ...
  normalizeProps(child, vm)
  normalizeInject(child, vm)
  normalizeDirectives(child)
  
 ...
  const options = {}
  let key
  for (key in parent) {
    mergeField(key)
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key)
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}

  • normalizeProps格式化props
  • normalizeInject格式化inject
  • normalizeDirectives格式化directives
  • mergeField合并函数,对每一个key采用对应的strats函数进行合并
strats是一个对象
activated: ƒ mergeHook( parentVal, childVal )
beforeCreate: ƒ mergeHook( parentVal, childVal )
beforeDestroy: ƒ mergeHook( parentVal, childVal )
beforeMount: ƒ mergeHook( parentVal, childVal )
beforeUpdate: ƒ mergeHook( parentVal, childVal )
components: ƒ mergeAssets( parentVal, childVal, vm, key )
computed: ƒ ( parentVal, childVal, vm, key )
created: ƒ mergeHook( parentVal, childVal )
data: ƒ ( parentVal, childVal, vm )
deactivated: ƒ mergeHook( parentVal, childVal )
destroyed: ƒ mergeHook( parentVal, childVal )
directives: ƒ mergeAssets( parentVal, childVal, vm, key )
el: ƒ (parent, child, vm, key)
errorCaptured: ƒ mergeHook( parentVal, childVal )
filters: ƒ mergeAssets( parentVal, childVal, vm, key )
inject: ƒ ( parentVal, childVal, vm, key )
methods: ƒ ( parentVal, childVal, vm, key )
mounted: ƒ mergeHook( parentVal, childVal )
props: ƒ ( parentVal, childVal, vm, key )
propsData: ƒ (parent, child, vm, key)
provide: ƒ mergeDataOrFn( parentVal, childVal, vm )
serverPrefetch: ƒ mergeHook( parentVal, childVal )
updated: ƒ mergeHook( parentVal, childVal )
watch: ƒ ( parentVal, childVal, vm, key )
data,provide合并
// 代码截取
  if (!childVal) {
      return parentVal
    }
    if (!parentVal) {
      return childVal
    }
  ...
  //mergeData
  if (!hasOwn(to, key)) {
      set(to, key, fromVal) // 响应式添加
    } else if (
      toVal !== fromVal &&
      isPlainObject(toVal) &&
      isPlainObject(fromVal)
    ) {
      mergeData(toVal, fromVal) // 递归赋值
    }
  • 如果parentVal不存在,返回childVal
  • 如果childVal不存在,返回parantVal
  • 如果都存在,遍历parantVal的key
    • 如果childVal不存在key,则把parantVal的这个属性响应式赋值给childVal
    • 如果childVal存在key,对应的值不相等并且是对象,则递归这个对象进行赋值
    • 最后返回childVal
props,methods,inject,computed合并
 if (!parentVal) return childVal
  const ret = Object.create(null)
  extend(ret, parentVal)
  if (childVal) extend(ret, childVal)
  return ret
  • 如果parentVal不存在,则返回childVal
  • 如果childVal不存在,则返回parentVal
  • 创建一个对象把parentVal,childVal继承返回,后者覆盖前者
'beforeCreate', 'created', 'beforeMount', 'mounted','beforeUpdate', 'updated', 'beforeDestroy', 'destroyed', 'activated', 'deactivated', 'errorCaptured', 'serverPrefetch'合并
 const res = childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
  return res
    ? dedupeHooks(res)
    : res
// dedupeHooks
function dedupeHooks (hooks) {
  const res = []
  for (let i = 0; i < hooks.length; i++) {
    if (res.indexOf(hooks[i]) === -1) {
      res.push(hooks[i])
    }
  }
  return res
}

  • childVal不存在,返回parentVal
  • parentVal不存在,返回[childVal]
  • 都存在采用合并数组,parentVal.concat(childVal)
  • dedupeHooks排重
'component', 'directive', 'filter'合并
  const res = Object.create(parentVal || null)
  if (childVal) {
    return extend(res, childVal)
  } else {
    return res
  }
  • childVal不存在,返回parentVal
  • parentVal不存在,返回childVal
  • 如果都存在,继承parentVal,childVal,后者覆盖前者

小节:

  • 了解Vue的静态方法
  • mergeOptions对options合并规则
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352