Skip to content

Commit

Permalink
chore: manually mount
Browse files Browse the repository at this point in the history
  • Loading branch information
w2xi committed Jan 24, 2024
1 parent b041ea0 commit a209e40
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
5 changes: 4 additions & 1 deletion demo/mount.html → demo/22-manually-mount.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
.red {
color: red;
}
li {
cursor: pointer;
}
</style>
<body></body>
<script>
Expand All @@ -11,7 +14,7 @@
props,
children,
}
}
}

function render() {
return h('ul', {
Expand Down
Binary file added public/vnode-to-dom.excalidraw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 98 additions & 1 deletion slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -2165,7 +2165,104 @@ function compileToFunction(template) {

## 挂载&更新

前面我们实现了 **响应式系统****编译**(丐中丐版),现在我们将它们整合起来,同时为了能将代码跑起来,我们还需要稍微简单实现下 **挂载和更新** (这里不涉及 patch)。
前面我们实现了 **响应式系统****编译**(丐中丐版),已经有能力将模板编译成渲染函数了,现在我们将它们整合起来,同时为了能将代码跑起来,我们还需要稍微简单实现下 **挂载和更新** (这里不涉及 patch)。

过程如下图所示:

<img src="/public/vnode-to-dom.excalidraw.png" />

---

对于下面的模板:

```html
<ul class="red">
<li>Vue</li>
<li>React</li>
<li>Angular</li>
</ul>
```

经过编译后,其对应的渲染函数和VNode分别如下:

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

```js
function render() {
return h('ul', {
class: 'red',
onClick() {
console.log('click')
}
},
[
h('li', null, 'Vue'),
h('li', null, 'React'),
h('li', null, 'Angular')
]
)
}
```

```js
// VNode
{
tag: 'ul',
props: {
class: 'red',
onClick() {
console.log('click')
}
},
children: [
{ tag: 'li', children: 'Vue' },
{ tag: 'li', children: 'React' },
{ tag: 'li', children: 'Angular' },
]
}
```

</div>

---

渲染函数的执行会生成虚拟 DOM,接下来我们尝试手动将虚拟 DOM 渲染到页面上。

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

```js
function mount(vnode, container) {
const el = document.createElement(vnode.tag)
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])
}
}
}
if (Array.isArray(vnode.children)) {
vnode.children.forEach(child => {
mount(child, el)
})
} else {
el.textContent = vnode.children
}
container.appendChild(el)
}
```

```js
// demo: 22-manually-mount.html

const vnode = render()
console.log(vnode);
mount(vnode, document.body)
```

</div>

---

Expand Down

0 comments on commit a209e40

Please sign in to comment.