diff --git a/docs/frontEnd/sourceCode/vue3.md b/docs/frontEnd/sourceCode/vue3.md index 67924c6..26dd5a4 100644 --- a/docs/frontEnd/sourceCode/vue3.md +++ b/docs/frontEnd/sourceCode/vue3.md @@ -12,7 +12,7 @@ slug: /frontEnd/sourceCode/vue3 ## 简单 diff 算法 -### 减少 dom 操作的性能和开销 +### 减少 DOM 操作的性能和开销 针对这样一个例子: @@ -49,11 +49,11 @@ function patchChildren(n1, n2, container) { const newLen = newChildren.length const commonLength = Math.min(oldLen, newLen) for (let i = 0; i < commonLength; i++) { - patch(oldChildren[i], newChildren[i]) + patch(oldChildren[i], newChildren[i], container) } if (newLen > oldLen) { for (let i = commonLength; i < newLen; i++) { - patch(null, newChildren[i]) + patch(null, newChildren[i], container) } } else if (newLen < oldLen) { for (let i = commonLength; i < oldLen; i++) { @@ -65,3 +65,62 @@ function patchChildren(n1, n2, container) { } } ``` + +### DOM 复用与 key 的作用 + +有下面一种情况: + +```js +// oldChildren +const old = [{ type: 'p' }, { type: 'div' }, { type: 'span' }] + //newChildren +const new = [{ type: 'span' }, { type: 'p' }, { type: 'div' }] + +``` + +如果采用上面的方法,由于 type 不同,调用 patch 函数时,总共会有 6 次的`DOM`操作,但是实际上`oldChildren`和`newChildren`实际上只有顺序不同,因此只需要进行`DOM`的移动操作即可。 + +实际操作中,我们需要引入`key`属性来作为标识来帮助判断如何移动`DOM`。 + +```js +const old = [ + { type: 'p', children: '1', key: 1 }, + { type: 'p', children: '2', key: 2 }, + { type: 'p', children: '3', key: 3 }, +] + +const new = [ + { type: 'p', children: '3', key: 3 }, + { type: 'p', children: '1', key: 1 }, + { type: 'p', children: '2', key: 2 }, +] +``` + +`key`属性就像身份证,只要`type`属性和`key`属性相同,我们便可以认为他们可以进行`DOM`复用。注意:这里可以进行`DOM`复用并不意味着不需要更新。 + +```js +function patchChildren(n1, n2, container) { + if (typeof n2.children === 'string') { + // 省略代码 + } else if (Array.isArray(n2.children)) { + const oldChildren = n1.children + const newChildren = n2.children + for (let i = 0; i < newChildren.length; i++) { + const newNode = newChildren[i] + for (let j = 0; j < oldChildren.length; j++) { + const oldNode = oldChildren[j] + if (newNode.key === oldNode.key) { + patch(oldNode, newNode, container) + break + } + } + } + } else { + // 省略代码 + } +} +``` + +这里只考虑`patch`内容,下面再考虑移动`DOM`。 + +### 找到需要移动的元素