我们在分析mount时候,最后抛出了两个问题,其中一个就是update函数拿到render生成的vNode后做了什么?
首先打开src\core\instance\lifecycle.js,找到_update函数,该函数在初始化时被挂载至vue
该函数的入参为
和false
向下走,prevEl缓存了一份<div class="app"></div>;vm指向vue;prevVnode=undefined
if (!prevVnode)取值为true,调用vm.__patch__方法
首先找到文件src\platforms\web\runtime\patch.js
在该文件中导入的nodeOps是一个原生dom操作集合,如insertBefore、appendChild、createElement等
baseModules和platformModules则是生成dom所需要的工具模块,他们最后的合集modules形如
createPatchFunction则是path的核心方法,该方法首先做了一次for循环
循环结束后实际上相当于让cbs缓存了一份modules
之后将内部定义的私有方法patch返回到_update中并调用,也就是说,在_update中调用的就是createPatchFunction返回的函数,其接收的形参为
对应的实参为
函数调用依次向下执行
由于oldVnode.nodeType=1,因此isRealElement=true,代码走向else逻辑
由于oldVnode.hasAttribute(SSR_ATTR)=false && hydrating=false
因此直接调用emptyNodeAt
该方法将返回一个vnode实例,生成的vnode如下,即
接着拿到当前的<div id="app">和body元素
紧接着调用createElm,该方法的入参为
代码向下走
isDef(tag)=true进入判断
nodeOps.createElement调用原生dom方法创建了div元素
setScope是一些作用域相关的操作,如style标签设置scoped后css只在当前页有效
__WEEX__=false走向else逻辑
createChildren则是真的children,将每一个children成员遍历执行createElm,也就是说,他的结果也是创建一些html标签,由于我们这里是空数组,故忽略
invokeCreateHooks则向data属性上安装了一些钩子
insert则调用原生domAPI向html中插入dom元素
此时我们的页面实际上有两个id为app的div元素
回到patch
isDef(vnode.parent)=false不进入代码块
isDef(parentElm)=true调用removeVnodes
该方法的入参为
因此,for循环只会执行一次,调用removeAndInvokeRemoveHook
该方法经过一系列的if判断最终会调用createRmCb,而createRmCb方法实际上是调用了元素domAPI的removeChild方法将其中一个id为app的元素删除
也就是说,_update的过程实际上就是调用原生domAPI对el指定的标签元素进行copy+remove操作
那么,如果是组件,又将如何被转化为dom呢?(组件vnode的dom化)
网友评论