From 7ffb22179b4327057e9dd47777eb70b07172ad45 Mon Sep 17 00:00:00 2001 From: w2xi <43wangxi@gmail.com> Date: Mon, 29 Jan 2024 13:08:16 +0800 Subject: [PATCH] chore: adjust demo --- demo/23-force-update.html | 94 +++++++++++++++++++++++++++++++++++++++ slides.md | 72 +++++++++++++++++++++++++++--- 2 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 demo/23-force-update.html diff --git a/demo/23-force-update.html b/demo/23-force-update.html new file mode 100644 index 0000000..b403b87 --- /dev/null +++ b/demo/23-force-update.html @@ -0,0 +1,94 @@ +<style> + .demo { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + .count { + margin: 0 15px; + } +</style> + +<body> + <div id="app"> + <div class="demo"> + <button @click="minus">-1</button> + <span class="count">{{ count }}</span> + <button @click="plus">+1</button> + </div> + </div> +</body> + +<script src="./static/mini-vue.umd.js"></script> + +<script> +const { ref, effect, proxyRefs, compileToFunction } = MiniVue + + +createApp({ + setup() { + const count = ref(0) + const plus = () => { + count.value++ + } + const minus = () => { + count.value-- + } + return { + count, + plus, + minus + } + } +}).mount('#app') + +function createApp(options = {}) { + const app = { + mount(container) { + if (typeof container === 'string') { + container = document.querySelector(container) + } + const template = container.innerHTML + const { render } = compileToFunction(template) + const setupFn = options.setup || noop + const setupResult = setupFn() || {} + const data = proxyRefs(setupResult) + const reload = () => { + const vnode = render(data) + container.innerHTML = '' + _mount(vnode, container) + } + effect(() => { + reload() + }) + } + } + return app +} + +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 { // string + el.textContent = vnode.children + } + + container.appendChild(el) +} +</script> + diff --git a/slides.md b/slides.md index e39d225..d60caf4 100644 --- a/slides.md +++ b/slides.md @@ -2192,11 +2192,18 @@ function compileToFunction(template) { [Vue3 Template Explorer](https://template-explorer.vuejs.org/) +--- +layout: center +transition: fade-out +--- + +# 挂载&更新 + --- -## 挂载&更新 +## 挂载 -前面我们实现了 **响应式系统** 和 **编译**(丐中丐版),已经有能力将模板编译成渲染函数了,现在我们将它们整合起来,同时为了能将代码跑起来,我们还需要稍微简单实现下 **挂载和更新** (这里不涉及 patch)。 +前面我们实现了 **响应式系统** 和 **编译**(丐中丐版),已经有能力将模板编译成渲染函数了,现在我们将它们整合起来,同时为了能将代码跑起来,我们还需要稍微简单实现下 **挂载**。 过程如下图所示: @@ -2304,7 +2311,9 @@ mount(vnode, document.body) --- -前文中,我们已经实现了**挂载**,现在我们将代码封装一下,并实现自动**更新**的功能。 +## 更新 + +前文中,我们已经实现了**挂载**,现在我们将代码封装一下,并实现**更新**的功能。 <div grid="~ cols-2 gap-2"> @@ -2334,9 +2343,7 @@ function createApp(options = {}) { container.innerHTML = '' _mount(vnode, container) } - effect(() => { - reload() - }) + effect(() => reload()) } } return app @@ -2349,7 +2356,58 @@ function createApp(options = {}) { 现在代码应该可以跑起来了,并且能够响应式更新。 -接下来来看一个 **计数器 demo**。 +但是这里的更新目前其实是: 先把 dom 清空,然后再重新挂载的一个过程。 + +来看一个 demo: + +<div grid="~ cols-2 gap-2"> + +```html +<body> + <div id="app"> + <div class="demo"> + <button @click="minus">-1</button> + <span class="count">{{ count }}</span> + <button @click="plus">+1</button> + </div> + </div> +</body> + +<script src="./static/mini-vue.umd.js"></script> + +<script> +const { ref, effect, proxyRefs, compileToFunction } = MiniVue +</script> +``` + +```js +// demo: 23-force-update.html + +createApp({ + setup() { + const count = ref(0) + const plus = () => { + count.value++ + } + const minus = () => { + count.value-- + } + return { + count, + plus, + minus + } + } +}).mount('#app') +``` + +</div> + +--- + +运行 demo,点击 `+1` 按钮,查看 DevTools 的 Elements,发现每次都是全量更新。 + +接下来我们来简单优化下,实现一个简单的 `patch` 函数,用来对比新旧节点,只更新需要更新的部分。 ---