写点什么

【Vue2.x 源码学习】第二十篇 - 使用真实节点替换原始节点

用户头像
Brave
关注
发布于: 1 小时前
【Vue2.x 源码学习】第二十篇 - 使用真实节点替换原始节点

一,前言


上篇,根据 vnode 虚拟节点创建真实节点,主要涉及以下几点:

  • vnode 渲染真实节点的步骤

  • Vue 原型方法 _update 的扩展

  • patch 方法中的两个步骤:1,创建真实节点;2,替换掉老节点

  • createElm 实现:根据虚拟节点创建真实节点


本篇,使用真实节点替换原始节点


二,新老节点的替换更新


目前为止,仅是围绕根节点的实现,尚未涉及组件的更新

1,前情回顾

前面,通过 createElm 完成了根据虚拟节点生成真实节点,详细步骤如下:

  1. 通过 vnode 中 tag 判断是元素还是文本:文本的 tag 为 undefined

  2. 如果当前节点是文本,创建文本真实节点:document.createTextNode(text)

  3. 如果当前节点是元素,创建元素真实节点:document.createElement(tag)

当前节点是元素且存在儿子,继续递归创建儿子的真实节点,并添加到对应的父亲中:

children.forEach(child => {el.appendChild(createElm(child))});

4,返回生成的真实节点


下面继续,使用真实节点替换原始节点

2,新老节点的更新方案


那么,如何进行新老节点的替换?

若使用 replace 方法进行 dom 替换,就需要找到父节点,还需要指定用谁替换谁,使用起来不方便


Vue 的实现方式:

1,找到老节点;

2,将新节点插入到老节点之后,新老为兄弟节点;

3,删除老节点;

这种实现的优势是:能够确保在新老节点完成更新后,文档的顺序不变;

3,虚拟节点与真实节点映射


问题:为什么要做真实节点与虚拟节点的映射关系?

当虚拟节点被更新时,便于跟踪并找到与之【vnode】对应的真实节点【el】,完成真实节点的更新操作


代码实现:

将真实节点绑定到 vnode 扩展属性 el 上:

function createElm(vnode) {  let{tag, data, children, text, vm} = vnode;  // vnode.el:绑定真实节点与虚拟节点的映射关系,便于后续的节点更新操作	if(typeof tag === 'string'){    vnode.el = document.createElement(tag) // 创建元素的真实节点		updateProperties(vnode.el, data)	// 处理元素的 data 属性    // 处理当前元素节点的儿子:递归创建儿子的真实节点,并添加到对应的父亲中    children.forEach(child => { // 若不存在儿子,children为空数组      vnode.el.appendChild(createElm(child))    });  } else { // 文本:文本中 tag 是 undefined    vnode.el = document.createTextNode(text)	// 创建文本的真实节点  }  return vnode.el;}
复制代码

4,实现新老节点的替换


根据新老节点的更新方案:

  1. 找到元素的父亲节点

  2. 找到老节点的下一个兄弟节点

  3. 将新节点插入到老节点的下一个兄弟节点前面

  4. 删除老节点

/** * 将虚拟节点转为真实节点后插入到元素中 * @param {*} el    当前真实元素 id#app * @param {*} vnode 虚拟节点 * @returns         新的真实元素 */export function patch(el, vnode) {  console.log(el, vnode)  // 1,根据虚拟节点创建真实节点  const elm = createElm(vnode);  console.log("createElm", elm);
// 2,使用真实节点替换掉老节点 // 找到元素的父亲节点 const parentNode = el.parentNode; // 找到老节点的下一个兄弟节点(nextSibling 若不存在将返回 null) const nextSibling = el.nextSibling; // 将新节点elm插入到老节点el的下一个兄弟节点nextSibling的前面 // 备注:若nextSibling为 null,insertBefore 等价与 appendChild parentNode.insertBefore(elm, nextSibling); // 删除老节点 el parentNode.removeChild(el);
return elm;}
复制代码


至此,就完成 Vue 文档中的“Create vm.$el and replace 'el' with it”,即完成了 Vue 的初始化流程


后面,当时数组更新时,Vue 将通过 diff 算法进行组件级别的更新,这就需要进行依赖收集


三,结尾


还剩最后 1 篇了,全程没有特别的划水,还算是比较欣慰;

为了让这些文章日后能更有价值,后续还要挨篇优化;


本篇,使用真实节点替换原始节点,主要涉及以下几点:

  • 新老节点的更新方案

  • 虚拟节点与真实节点映射

  • 实现新老节点的替换


下一篇,依赖收集的过程分析


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vue2.x 源码学习】第二十篇 - 使用真实节点替换原始节点