Skip to content

Commit

Permalink
feat: DOM复用和key的作用
Browse files Browse the repository at this point in the history
  • Loading branch information
jaluik committed Mar 3, 2023
1 parent 129b0d6 commit 29aa55d
Showing 1 changed file with 62 additions and 3 deletions.
65 changes: 62 additions & 3 deletions docs/frontEnd/sourceCode/vue3.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ slug: /frontEnd/sourceCode/vue3

## 简单 diff 算法

### 减少 dom 操作的性能和开销
### 减少 DOM 操作的性能和开销

针对这样一个例子:

Expand Down Expand Up @@ -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++) {
Expand All @@ -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`

### 找到需要移动的元素

0 comments on commit 29aa55d

Please sign in to comment.