【vue2源码学习】— 组件节点

在看createElement方法时我们了解到_createElement 方法里面对 tag 的判断,
如果是一个常规的 html 标签,比如 div,
会实例化一个 VNode 节点,
否则使用 createComponent 创建一个组件 VNode。
比如这种,拿到App进行的处理,
会使用 createComponent 创建一个组件 VNode
import Vue from 'vue'
import App from './App.vue'
var app = new Vue({
  el: '#app',
  render: h => h(App)
})
// 这种就会创建普通的div节点
const vm = new Vue({
	render: c=>{
     return (
       c('div', {}, [['1', '2', '3']])
     )
   }
 })
//createComponent的定义在 src/core/vdom/create-component
export function createComponent (
  Ctor: Class<Component> | Function | Object | void,
  data: ?VNodeData,
  context: Component,
  children: ?Array<VNode>,
  tag?: string
): VNode | Array<VNode> | void {
  ...
  const baseCtor = context.$options._base

  // plain options object: turn it into a constructor
  // 把对象转换为构造函数
  if (isObject(Ctor)) {
    Ctor = baseCtor.extend(Ctor)
  }
	...
  // async component
  let asyncFactory
  ... 异步相关处理

  data = data || {}

  // resolve constructor options in case global mixins are applied after
  // component constructor creation
  resolveConstructorOptions(Ctor)

  // transform component v-model data into props & events
  if (isDef(data.model)) {
    transformModel(Ctor.options, data)
  }

  // extract props
  const propsData = extractPropsFromVNodeData(data, Ctor, tag)

 ...函数式组件
 ...监听器、参数等处理

  // install component management hooks onto the placeholder node
  installComponentHooks(data)

  // return a placeholder vnode
  const name = Ctor.options.name || tag
  const vnode = new VNode(
    `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
    data, undefined, undefined, undefined, context,
    { Ctor, propsData, listeners, tag, children },
    asyncFactory
  )

	...__WEEX__相关
  return vnode
}

组件渲染主要3个步骤:
生成构造函数,安装组件钩子函数和实例化 vnode
// 平常我们的 xx.vue文件
export default {
。。。
}
export 的是一个对象,所以会执行 baseCtor.extend(Ctor),
baseCtor 实际上就是 Vue,定义在最开始初始化 Vue 的阶段,
在 src/core/global-api/index.js 的initGlobalAPI有一行:
---
Vue.options._base = Vue
---
在 src/core/instance/init.js 的 Vue 原型上 _init 函数中:
---
vm.$options = mergeOptions(
  resolveConstructorOptions(vm.constructor),
  options || {},
  vm
)
---
mergeOptions的功能是把 Vue 构造函数的 options 
和用户传入的 options 合并到 vm.$options 上
Vue.extend 定义在 src/core/global-api/extend.js 的initExtend中
  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
	...
    const Sub = function VueComponent (options) {
      this._init(options)
    }
	...继承处理
    cachedCtors[SuperId] = Sub
    return Sub
  }
Vue.extend 作用是构造 Vue 的子类
然后对 Sub 这个对象本身扩展了一些属性
实例化 Sub,就会执行 this._init 就回到了 Vue 实例的初始化

installComponentHooks 是把 componentVNodeHooks 的钩子函数
合并到 data.hook 中,patch 的时候执行相关的钩子函数
// inline hooks to be invoked on component VNodes during patch
const componentVNodeHooks = {...}
function installComponentHooks (data: VNodeData) {
  const hooks = data.hook || (data.hook = {})
  for (let i = 0; i < hooksToMerge.length; i++) {
    const key = hooksToMerge[i]
    const existing = hooks[key]
    const toMerge = componentVNodeHooks[key]
    if (existing !== toMerge && !(existing && existing._merged)) {
      hooks[key] = existing ? mergeHook(toMerge, existing) : toMerge
    }
  }
}

function mergeHook (f1: any, f2: any): Function {
  const merged = (a, b) => {
    // flow complains about extra args which is why we use any
    f1(a, b)
    f2(a, b)
  }
  merged._merged = true
  return merged
}
合并过程中,某个钩子已经存在 data.hook 中,通过执行 mergeHook 合并
执行的时候,依次执行这两个函数就行了

最后通过 new VNode 实例化一个 vnode 并返回。
值得注意的是和普通 vnode 相比组件的 vnode 是没有 children 的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值