Skip to content

Commit

Permalink
chore: adjust patch
Browse files Browse the repository at this point in the history
  • Loading branch information
w2xi committed Jan 29, 2024
1 parent 48f0508 commit 8a5017a
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 6 deletions.
127 changes: 127 additions & 0 deletions demo/24-patch.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<style>
.red { color: red; }
.green { color: green; }
</style>

<body>
<div id="app"></div>
</body>

<script>
function h(tag, props, children) {
return {
tag,
props,
children,
}
}

function mount(vnode, container) {
const el = vnode.el = document.createElement(vnode.tag);
vnode.parent = container
// handle props
if (vnode.props) {
for (let key in vnode.props) {
if (key.startsWith('on')) { // 事件绑定
const eventName = key.slice(2).toLowerCase();
el.addEventListener(eventName, vnode.props[key]);
} else {
el.setAttribute(key, vnode.props[key]);
}
}
}
// handle children
if (vnode.children) {
if (Array.isArray(vnode.children)) {
vnode.children.forEach(child => {
mount(child, el);
});
} else { // text node
el.textContent = vnode.children;
}
}

container.appendChild(el);
}

const vdom = h('div', { class: 'red' }, [
h('span', null, 'hello')
])

mount(vdom, document.getElementById('app'))

function patch(n1, n2) {
// there are lots of assumption and only handle simpler cases

// patch tag
if (n1.tag === n2.tag) {
const el = n1.el
// patch props
const oldProps = n1.props || {}
const nweProps = n2.props || {}
for (const key in nweProps) {
const oldValue = oldProps[key]
const newValue = nweProps[key]
if (oldValue !== newValue) {
el.setAttribute(key, newValue)
}
}
// patch children
const oldChildren = n1.children
const newChildren = n2.children
if (typeof newChildren === 'string') {
if (typeof oldChildren === 'string') {
if (newChildren !== oldChildren) {
el.textContent = newChildren
}
} else {
// oldChildren is a array, but we can just override it
el.textContent = newChildren
}
} else {
if (typeof oldChildren === 'string') {
// discard oldChildren
el.innerHTML = ''
// mount newChildren
newChildren.forEach(child => {
mount(child, el)
})
} else {
// both old and new is a array

const commonLength = Math.min(oldChildren.length, newChildren.length)
for (let i = 0; i < commonLength; i++) {
patch(oldChildren[i], newChildren[i])
}
if (newChildren.length > oldChildren.length) {
// to new node, just mount it
newChildren.slice(oldChildren.length).forEach(child => {
mount(child, el)
})
} else if (newChildren.length < oldChildren.length) {
oldChildren.slice(newChildren.length).forEach(child => {
// unmount old el
el.removeChild(child.el)
})
}
}
}
} else {
// ... replace

// unmount old dom
n1.parent.removeChild(n1.el)
// mount new dom
mount(n2, n1.parent)
}
}

const vdom2 = h('div', { class: 'green' }, [
h('span', null, 'changed!')
])

setTimeout(() => {
patch(vdom, vdom2)
}, 1000)

</script>
File renamed without changes.
Binary file modified public/patch.excalidraw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 32 additions & 6 deletions slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -1351,7 +1351,7 @@ const ast = {
}
```

定义节点类型:
定义节点类型枚举:

```js
const NodeTypes = {
Expand Down Expand Up @@ -2415,9 +2415,36 @@ createApp({

---

`patch` 函数的实现如下:

```js
/**
* @param {*} n1 old vnode
* @param {*} n2 new vnode
*/
function patch(n1, n2) {
if (n1.tag === n2.tag) {
// ...
} else {
// ...
}
}
```

具体代码和demo见: `24-patch.html`

---

现在,我们已经实现了 **挂载****更新**,整合之前的代码,接下来再来看下 **计数器** demo 的效果。

---

## Counter 计数器

demo: `22-counter.html`
demo: `25-counter.html`

> 打开 DevTools 的 Elements 查看效果

<div grid="~ cols-2 gap-2">

Expand Down Expand Up @@ -2497,9 +2524,9 @@ function createApp(options = {}) {
<div id="app"></div>
```

```html
<script>
// demo: 24-render-function-options.html
```js
// demo: 26-render-function-options.html

const { createApp, ref, h } = MiniVue
createApp({
setup() {
Expand All @@ -2521,7 +2548,6 @@ createApp({
])
}
}).mount('#app')
</script>
```

</div>
Expand Down

0 comments on commit 8a5017a

Please sign in to comment.