但是这个结构是可执行的,可编译的,通过with的方式改变this的上下文,动态执行每个可执行的代码部分,并把每个节点部分都编译成vnode,组成一个有对应层次结构的vnode对象
举例来说
div是最外层的vnode
div有子节点=> p,生成对应vnode
p有子节点=>文本节点answer,生成对应vnode
每个vnode会保存每个对应节点一些计算信息,比如tag、data、 children、text这些都是用于后面的比对计算的
vm._update
通过render拿到了vnode,然后通过update对比vnode绘制到页面
update这个方法内部有段代码
vm.$el = vm.__patch__(prevVnode, vnode);
从这个字面意思就明显知道,更新补丁,用于对比新旧2个vnode,
vue2有个专门的patch文件用于vnode的对比策略,patch内部会细分很多策略出来
如果vnode不存在但是oldVnode存在,就意味着要销毁
如果oldVnode不存在但是vnode存在,说明意图是要创建新节点
当vnode和oldVnode都存在时,就需要更新了
每一种策略都对应的不同的处理方式,更新才意味着需要对比新旧的vnode,首先是需要判断下两个节点是否值得比较,在这个例子里面只改变了属性input与answer的值,所以,这里是属于同节点内的属性变更的,所以检测vnode的变化也是相对最简单,递归子节点,通过patchVnode检测每个节点属性的变化
if(sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
}
当对比到差异时,例如文本answer被改变,那么对应的vnode在对比的时候,就能找到差异,然后重新设置值,此刻的node就是真实的DOM引用的,如果改变了textContent就意味着页面上呈现的数据就直接被改变了
if (oldVnode.text !== vnode.text) {
nodeOps.setTextContent(elm, vnode.text);
}
function setTextContent (node, text) {
node.textContent = text;