src=${value} alt=""/>`; document.getElementById("wrapper").appendChild(impressionHtml); js向父元素wrapper中的末尾添加...定义好的html,报错: Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type...在stackoverflow上找到很好的一个解释: ? 所以js是不能直接传入字符串的,但是jquery的append可以直接传入html字符串。
有如下树形结构:RT-ST-SST-SSST共四层,RT是根节点,往后依次是一代子节点,二代子节点,三代子节点。 如何根据当前节点的id,获得其子节点呢?这是一个SQL问题。...加入传入的id为1(即根节点),使用自连+SUBSTRING_INDEX函数得到其子节点: 示例: id name type url 1 大树 RT root...为1(即根节点),使用自连+SUBSTRING_INDEX函数得到其子节点: mysql> select tree1.* from tree_node as tree1 -> join tree_node...url and (length(tree1.url) - length(replace(tree1.url, '/', ''))) = 1 where tree2.id = 1; ##返回"树干1"的父节点的...1,则认为是子节点 mysql> select length('root/tree_main_line1') - length(replace('root/tree_main_line1', '/',
oldCh, ch) }else if (ch){ //如果新节点有子节点而老节点没有子节点,那么将新节点的子节点添加到老节点上 createEle...(vnode) }else if (oldCh){ //如果新节点没有子节点而老节点有子节点,那么删除老节点的子节点 api.removeChildren...(el) } }}如果两个节点不一样,直接用新节点替换老节点;如果两个节点一样,新老节点一样,直接返回;老节点有子节点,新节点没有:删除老节点的子节点;老节点没有子节点,新节点有子节点...:新节点的子节点直接append到老节点;都只有文本节点:直接用新节点的文本节点替换老的文本节点;都有子节点:updateChildren最复杂的情况也就是新老节点都有子节点,那么updateChildren...index添加到真实DOM中;newStartIdx > newEndIdx表示ch先遍历完成,那么就要在真实DOM中将多余节点删除掉;看下图这个实例,就是新节点先遍历完成删除多余节点:图片最后,在这些子节点
当根节点发现子节点中 A 消失了,就会直接销毁 A;当 D 发现多了一个子节点 A,则会创建新的 A(包括子节点)作为其子节点。...INSERT_MARKUP,新的 component 类型不在老集合里, 即是全新的节点,需要对新节点执行插入操作。...REMOVE_NODE,老 component 类型,在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作,或者老 component 不在新集合里的,也需要执行删除操作...如下图,老集合中包含节点:A、B、C、D,更新后的新集合中包含节点:B、A、D、C,此时新老集合进行 diff 差异化对比,发现 B !...= A,则创建并插入 B 至新集合,删除老集合 A;以此类推,创建并插入 A、D 和 C,删除 B、C 和 D。
上篇文章《虚拟DOM如何进化为真实DOM》中讲到了如何通过虚拟DOM树转化为真实DOM渲染到页面中。但是在渲染的过程中,我们直接将新的虚拟DOM树转化成真实DOM替换掉旧的DOM结构。...platforms\web\runtime\modules\attrs.js 2、样式处理 如果老的样式中存在新的样式没有那么删除老的样式。...src\platforms\web\runtime\modules\class.js 比较儿子 在比较儿子的过程中可以分为以下几种情况: 1、老节点有儿子,新节点没有儿子删除老节点的儿子即可 if (...在vue2.0中比较老节点和新节点区别的时候采用了双指针的方式,通过同时向同一个方向循环老节点和新节点,只要有一个节点循环完成就结束循环。...在使用index作为key的时候还会产生意想不到的问题,假如我们把B节点删除,我们最开始取值为B,现在取值变成了C。
REMOVE_NODE,老 component 类型,在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作,或者老 component 不在新集合里的,也需要执行删除操作...如下图,老集合中包含节点:A、B、C、D,更新后的新集合中包含节点:B、A、D、C,此时新老集合进行 diff 差异化对比,发现 B !...新老集合所包含的节点,如下图所示,新老集合进行 diff 差异化对比,通过 key 发现新老集合中的节点都是相同的节点,因此无需进行节点删除和创建,只需要将老集合中节点的位置进行移动,更新为新集合中节点的位置...以上主要分析新老集合中存在相同节点但位置不同时,对节点进行位置移动的情况,如果新集合中有新加入的节点且老集合存在需要删除的节点,那么 React diff 又是如何对比运作的呢?...当完成新集合中所有节点 diff 时,最后还需要对老集合进行循环遍历,判断是否存在新集合中没有但老集合中仍存在的节点,发现存在这样的节点 D,因此删除节点 D,到此 diff 全部完成。
随机访问文档中的任一数据,可从父节点逐级遍历到目标节点。...如图,进行 Component Diff 时, 发现组件 D 和 G 是不同类型的组件,会直接删除组件 D 及其子节点,然后重新创建组件 G 及其子节点。...大多数算法都是采用 key 加 tagName 方式来进行对比,给每个子节点加上一个 key 作为唯一标志,这样既能有效复用老的 DOM 树上的节点,算法时间复杂度又不会很高。...操作,从而得到新的 DOM 树。...例如,相较于 Web 可以通过代码,透过 DOM 树修改 HTML 的内容,Android 布局资源是不可变的,只能在布局资源转换为视图后,在视图层面进行修改。
,reconcileChildFibers做的事情就是判断新节点newChild的类型,再决定如何协调。...{ // 本函数要做的事情就是diff新老vdom,在尽可能多的复用老vdom的情况下生成新的vdom,即fiber结构,并返回新的第一个子fiber, // 这个新的子fiber...step4: 走到现在,新老节点都还有,最麻烦的地方来了,也是React Diff的核心 // 经过上面的步骤,走到这里的新老vdom都是乱序的,因此接下来遍历新的vdom的时候,需要考虑的事情是如何去老...如果经过step1,新节点已经遍历完了,那么如果还有剩下的老节点,删除即可。 3. 如果经过step1,老节点没了,新节点还有,那么新节点逐个新增即可。初次渲染走的就是这里。 4....首先,根本上在于数据结构的不同,因为Vue的多个新子节点时候,老子节点就是数组,而React中则是单链表。
,那么没得比较了,所有节点都是全新的 所以直接全部新建就好了,新建是指创建出所有新DOM,并且添加进父节点的 2 只有旧节点 只有旧节点而没有新节点,说明更新后的页面,旧节点全部都不见了 那么要做的,就是把所有的旧节点删除...处理的是 新子节点 和 旧子节点,循环遍历逐个比较 如何 循环遍历?...1、比较新旧子节点 2、比较完毕,处理剩下的节点 我们来逐个说明这两个流程 1 比较新旧子节点 注:这里有两个数组,一个是 新子Vnode数组,一个旧子Vnode数组 在比较过程中,不会对两个数组进行改变...找到 新旧子节点中 的 相同的子节点,尽量以 移动 替代 新建 去更新DOM 只有在实在不同的情况下,才会新建 比较更新计划步骤 首先考虑,不移动DOM 其次考虑,移动DOM 最后考虑,新建 / 删除...newEndIdx ,结束循环 5 批量删除可能剩下的老节点 此时看 旧 Vnode 数组中, oldStartIdx 和 oldEndIdx 都指向同一个节点,所以只用删除 oldVnode-4 这个节点
,然后再去找当前节点的兄弟节点,直到找到 key 相同,并且节点的类型相同,否则就删除所有的子节点。...这已经是一个非常简单的例子了,div 的 child 是一个数组,有 AAA、BBB 然后还有其他的兄弟节点,在做 diff 的时候就可以从新旧的数组中按照索引一一对比,如果可以复用,就把这个节点从老的链表里面删除...新节点已经遍历完毕 如果新节点已经遍历完毕的话,也就是没有要更新的了,这种情况一般就是从原来的数组里面删除了元素,那么直接把剩下的老节点删除了就行了。还是拿上面的图的例子举例,老的链表里???...还有很多节点,而新的链表???已经没有节点了,所以老的链表???不管是有多少节点,都不能复用了,所以没用了,直接删除。...第一遍历完之后,删除剩余的老节点,追加剩余的新节点的过程。如果是新节点已遍历完成,就将剩余的老节点批量删除;如果是老节点遍历完成仍有新节点剩余,则将新节点直接插入。
操作,需要删除不需要的节点,更新修改过的节点,添加新的节点。...这个函数里面不能简单的创建新节点了,而是要将老节点跟新节点拿来对比,对比逻辑如下: 如果新老节点类型一样,复用老节点DOM,更新props 如果类型不一样,而且新的节点存在,创建新节点替换老节点 如果类型不一样...,没有新节点,有老节点,删除老节点 注意删除老节点的操作是直接将oldFiber加上一个删除标记就行,同时用一个全局变量deletions记录所有需要删除的节点: // 对比oldFiber...sameType && oldFiber) { // 如果类型不一样,没有新节点,有老节点,删除老节点 oldFiber.effectTag = 'DELETION';...虚拟DOM的调和和渲染可以简单粗暴的递归,但是这个过程是同步的,如果需要处理的节点过多,可能会阻塞用户输入和动画播放,造成卡顿。 Fiber是16.x引入的新特性,用处是将同步的调和变成异步的。
操作 DOM 后需要经过跨流程通信和渲染线程触发的重新渲染(重绘或者重排),在开发中,应尽量减少操作 DOM。而虚拟 DOM 出现后,更新 DOM 交给框架处理。...或 null,并且老虚拟节点有值 // 说明我们删除了节点,就调用 Destroy 生命周期钩子 if (isDef(oldVnode)) invokeDestroyHook...)) nodeOps.setTextContent(elm, ''); // 如果新的儿子有,老的儿子节点没有 // 会把新增的子节点插入到老的 DOM...,oldCh 是老的子节点;newCh 是新的子节点 let oldStartIdx = 0; // oldVnode 子节点初始索引 let newStartIdx = 0...oldKeyToIdx[newStartVnode.key] // 通过 key 可以拿到老的子元素的索引 // 如果新的开始元素没有 key,就遍历老的子节点,找到对应
patches来变成新节点,最终结果的基本雏形: let el = render(vnode)//老的虚拟dom树生成老html节点 document.body.appendChild(el) //挂载...//将当前差异数组写入差异表 currentPatch.length && (patches[index] = currentPatch) } 复制代码 对比属性: 我们传入新节点和老节点的属性集合...//如果属性不同,写入patch,老属性有,新属性没有或者不同,写入差异表 oldProp[k] !...== newProp[k] && (patch[k] = newProp[k]) } //新节点新属性 for(let k in newProp){ //判断老节点的属性在新节点里面是否存在,...== newProp[k] && (patch[k] = newProp[k]) } //新节点新属性 for(let k in newProp){ //判断老节点的属性在新节点里面是否存在,
patches来变成新节点,最终结果的基本雏形: let el = render(vnode)//老的虚拟dom树生成老html节点 document.body.appendChild(el) //挂载...//将当前差异数组写入差异表 currentPatch.length && (patches[index] = currentPatch) } 对比属性: 我们传入新节点和老节点的属性集合,进行遍历...,写入patch,老属性有,新属性没有或者不同,写入差异表 oldProp[k] !...== newProp[k] && (patch[k] = newProp[k]) } //新节点新属性 for(let k in newProp){ //判断老节点的属性在新节点里面是否存在,...== newProp[k] && (patch[k] = newProp[k]) } //新节点新属性 for(let k in newProp){ //判断老节点的属性在新节点里面是否存在,
Diff 的原理 核心源码:vue/src/core/vdom/patch.js 搬运对比新老节点 patch 函数入口 /** * 新节点不存在,老节点存在,调用 destroy,销毁老节点 * 如果.../** * 更新节点 * 如果新老节点都有孩子,则递归执行 updateChildren * 如果新节点有孩子,老节点没孩子,则新增新节点的这些孩子节点 * 如果老节点有孩子,新节点没孩子,则删除老节点这些孩子...< oldEndIdx) {} // 新节点先遍历结束,将剩余的旧节点删掉 } } 复制代码 Vue 中的 key 的作用 key 是 Vue 中 vnode 的唯一标记,我们的 diff 的算法中...sameVnode 用来判断是否为同一节点。常见的业务场景是一个列表,若 key 值是列表索引,在新增或删除的情况下会存在就地复用的问题。...updateChildren 中当其中四种假设都未匹配,就需要依赖老节点的 key 和 索引创建关系映射表,再用新节点的 key 去关系映射表去寻找索引进行更新,这保证 diff 算法更加快速。
基本元素的 receiveComponent基础元素的更新包括两方面属性的更新,包括对特殊属性比如事件的处理子节点的更新子节点的更新比较复杂,是提升效率的关键,所以需要处理以下问题:diff - 拿新的子节点树跟以前老的子节点树对比...我们需要把它对应的老的element删除。..._mountIndex = nextIndex; nextIndex++; } // 对于老的节点里有,新的节点里没有的那些,也全都删除掉 for (name in prevChildren...我们假设上一个元素是 A,添加后更新了 lastIndex。如果我们这时候来个新元素 B,比 lastIndex 还大说明当前元素在老的集合里面就比上一个 A 靠后。...,这里还会使用 lastIndex 这种做一种优化,使一些节点保留位置,之后根据差异对象操作 dom 元素(位置变动,删除,end这只是个玩具,但实现了 React 最核心的功能,虚拟节点,差异算法,单向数据更新都在这里了
领取专属 10元无门槛券
手把手带您无忧上云