Vue源码之v-model之组件

561 阅读3分钟

编译阶段之parse

template

ast

  • parse阶段
  • 在generate阶段有对el属性进行添加值的

流程

总结

1.在闭合标签后执行closeElement,然后执行processElement执行processAttrs。

2.processAttrs获取到el.attrsList,遍历判断name是否是指令,是的话获取修饰符通过对象返回出来。

3.判断name不为Bind不为on进入else逻辑,首先去掉v-标签,然后调用addDirective向el中添加directives属性。

4.如果name不是指令,调用addAttr向el中添加attrs属性。

编译阶段之generate

流程

总结

1.执行到generate阶段,执行genElement,执行genData,接着执行genDirectives函数。

2.接着执行genDirectives,首先获取到el.directives,遍历el.directives,然后获取平台定义的model函数,执行model函数。

3.model函数根据tag和type执行不同的解析逻辑,对于非表单元素的tag和type执行的是genComponentModel函数。

4.genComponentModell函数首先定义了回调事件表达式valueExpression = 'v'。

5.接着通过genAssignmentCode返回code,最终设置el的model属性。

6.genDirectives执行完毕,genData继续往下执行,这时el.model存在,根据el.model的值拼接data。

render & patch

流程

总结

image.png
image.png

子组件编译阶段之parse

流程

总结

1.在闭合标签后执行closeElement,然后执行processElement执行processAttrs。

2.processAttrs获取到el.attrsList,遍历判断name是否是指令,是的话获取修饰符通过对象返回出来。

3.判断name为v-bind指令,然后调用addProp向el中添加props属性。

4.判断name为v-on指令,然后调用addHandler向el中添加events属性。

子组件编译阶段之generate

流程

总结

1.执行到generate阶段,执行genElement,执行genData。

2.存在el.props,执行genProps,拼接data domProps属性。

3.存在el.events,执行genHandlers,首先根据标识确认输出nativeOn还是on属性名。接着遍历传入的el.events或者el.nativeEvents,然后通过执行genHandler获取到handlerCode,接着和事件名name拼接起来,最后再和之前确认的属性名进行拼接。

子组件patch

流程

总结

1.首先patch开始时会创建cbs对象和hooks,遍历Hooks为cbs添加hook属性为数组,接着继续遍历modules把modules定义相同hooks丢进数组中。最终返回cbs对象。

2.对于create除了按顺序执行存在data属性会调用invokeCreateHooks之外,在创建组件初始化完成时调用initComponent也会调用invokeCreateHooks。

3.invokeCreateHooks就是遍历调用cbs.create的函数,也就是执行updateDirectives,updateDOMListeners等钩子函数,传入空vnode和vnode。

4.updateDOMListeners获取到vnode.data.on对象和获取vnode.elm节点,执行updateListeners,遍历on对象,cur=createFnInvoker返回的函数,把回调赋值给了invoker.fns,此函数是执行回调用的,然后调用add也就是调用addEventListener给节点添加事件和此函数,案例中这里我们就为节点添加上了Input事件函数。

总结

给子组件的input添加了input事件,输入框输入后执行input事件,input事件触发了emit的input事件,那么他就去找组件实例上的_event.事件名,找到就执行触发回调。案例中的回调内容就是把msg设置为input输入的e.target.value。这样就完成了父子的通讯。

如果子组件不是input框,只是一个按钮事件。如下:

我们通过按钮点击触发emit的input事件一样把把msg设置为传出去的值。

接着就可以想到用语法糖去标识。如下:

对于自定义model是这样用的:

⼦组件修改了接收的 prop 名以及派发的事件名,然⽽这⼀切⽗组件作为调⽤⽅是不⽤关⼼的,这样做的好处是我们可以把 value 这个 prop 作为其它的⽤途。