普通slot
- 父组件update的时候已经创建了vnode, 子组件render的时候直接从$slot返回对应的vnode
父组件parse 阶段
- 往ast节点添加属性slot=slottarget, gendata生成对应字符串
- compile完 render, 创建子组件vnode后, 开始渲染子组件
|
|
|
|
genData 阶段
- 添加代码
"slot:" + (el.slotTarget) + ",
到render字符串中
|
|
子组件(compile) parse和gencode阶段
- 子组件在实例化的_init设置了$slots
initRender: vm.$slots = resolveSlots(options._renderChildren, renderContext);
- parse时slot ast节点添加slotName属性
- gencode拼上_t
|
|
|
|
运行时实现(子组件)
- 普通slot渲染时, 通过$slot返回父组件传过来的children vnode.
- 运行(调用render方法)时通过_t(renderSlot)生成vnode
|
|
2.6里slot和scope slot统一到scope slot, 优先从$scopedSlots获取
|
|
$slots来源
- 父组件调用$mount=>编译模板=>父组件渲染调用_render生成vnode
- 生成app-layout的vnode时, 先创建组件里面的children vnode作为参数传入
- 创建占位符节点后, patch vnode.
- patch时创建组件实例createChildren => componentVNodeHooks => createComponentInstanceForVnode=> 子组件new vue
- 子组件流程: init => initRender => resolveSlots
父组件提供
|
|
子组件获取
- 流程: init => initRender => resolveSlots
- 2.6后的render里适配成
$scopedSlots
|
|
scope-slot
父组件parse gencode
- 添加属性
el.slotScope = slotScope;
- 添加属性slotTarget
slot="xxx"
如果有的话 - 在closeElement里除了把节点添加到ast parent的children中(之后又删除), 还增加scopedSlots属性
currentParent.scopedSlots[name] = element
- 生成的render里没有children而是一个函数
fn: function(props) {}
, 参数就是slot-scope="props"
里面props
|
|
|
|
|
|
父组件运行时/render
|
|
子组件gencode render
- genslot时获取slot上绑定的props
- render时先获取
$scopedSlots
, 在执行_t(renderSlot) scopedSlotFn
中parent的属性在还是从parent获取, 而slot props从子组件传入的slot props获取
|
|
- 子组件_render时获取
$scopedSlots
, 是父组件提供data属性插入的
|
|
|
|
父组件更新子组件slot
- patchVnode => prepatch =>123456789101112131415161718function patchVnode () {var i;var data = vnode.data;if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {i(oldVnode, vnode);}}prepatch: function prepatch (oldVnode, vnode) {var options = vnode.componentOptions;var child = vnode.componentInstance = oldVnode.componentInstance;updateChildComponent(child,options.propsData, // updated propsoptions.listeners, // updated listenersvnode, // new parent vnodeoptions.children // new children);},
|
|