带你手写vue3核心源码(九)

Vue3 手写 Element 元素的props和children更新逻辑

之前我们实现了 element 元素的挂载,还没有实现当元素内的数据发生改变的时候,要对元素进行更新操作。

为此我准备了一个小 demo,期望用户在点击 button 按钮的时候能让count加一:

import { ref, h } from '../../lib/guide-toy-vue3.esm.js'
export const App = {name: 'app',setup() {const count = ref(0)const click = () => {count.value++}return {count,click,}},render() {return h('div', {}, [h('p', {}, `count: ${this.count}`),h('button', { onClick: this.click }, '点击更新'),])},
} 

[<img src=“https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a513919070734571998b2c0ab054dbe7~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)](https://link.juejin.cn/?target=https%3A%2F%2Fimgtu.com%2Fi%2FXwtJqU “https://imgtu.com/i/XwtJqU”” style=“margin: auto” />

可以看到 this.count 并没有打印出数值而是一个[Object object],为什么会这样呢?我们再进一步打印this.count是什么。

[<img src=“https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77efbc3a9dce4d86b4753beea097132c~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)](https://link.juejin.cn/?target=https%3A%2F%2Fimgtu.com%2Fi%2FXwtosf “https://imgtu.com/i/Xwtosf”” style=“margin: auto” />

他是一个 ref 对象,我们想要的值在_value里面,那要怎么去除这个值呢?我们之前是不是实现了proxyRefs,我当时说过他是用来在 h 函数里面自动解包 ref 的。

生怕你们忘了我在这里再贴一次这段代码的实现吧。

// 通常用在vue3 template里面ref取值,在template里面不需要.value就可以拿到ref的值
export function proxyRefs<T extends object>(obj: T) {return isReactive(obj)? obj: new Proxy<any>(obj, {get(target, key) {// unref已经处理了是否ref的情况所以我们不需要自己if处理,如果是,返回.value,如果不是,直接返回值return unref(Reflect.get(target, key))},set(target, key, value) {// 因为value为普通值类型的情况特殊,要把value赋值给ref的.valueif (isRef(target[key]) && !isRef(value)) {target[key].value = valuereturn true} else {return Reflect.set(target, key, value)}},})
} 

我们只需要对 setup 的返回值进行解包就好了。

在 runtime-core 里面的 component.ts 里面添加 proxyRefs 的调用操作

function handleSetupResult(instance: any, setupResult: any) {// TODO handle functionif (isFunction(setupResult)) {instance.render = setupResult} else if (isObject(setupResult)) {// 把setup返回的对象挂载到setupState上proxyRefs对setupResult解包instance.setupState = proxyRefs(setupResult) // 新增}
} 

这样 ref 的 value 就能正常显示出来了。

[<img src=“https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/569ff67b4a644e2f9fa3156399bddf45~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)](https://link.juejin.cn/?target=https%3A%2F%2Fimgtu.com%2Fi%2FXwUu3n “https://imgtu.com/i/XwUu3n”” style=“margin: auto” />

下一步我们来完成元素的更新

页面上的元素都是虚拟 dom 对象

{type: 'div',props: {},children:{},el: {},shapeFlag: 2...
} 

元素更新的时候需要生成新的 vnode 对象,然后通过旧的 vnode 和新的 vnode 进行对比,从而找出要更新的地方。如果是文本更新,那我们可以用 dom.textContext 属性更新。 [<img src=“https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a0831c83bf64720b500a70845569370~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image)](https://link.juejin.cn/?target=https%3A%2F%2Fimgtu.com%2Fi%2FXgflVI “https://imgtu.com/i/XgflVI”” style=“margin: auto” />

前提是我们需要获取旧的 vnode 和新的 vnode。新的 vnode 怎么获取?重新执行一次render函数就可以了啊,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值