手写 Vue3 数据双向绑定 理解Proxy

本文探讨了Vue3中的Proxy特性,解释了如何使用Proxy实现数据双向绑定,并对比了与Vue2的差异。通过示例展示了如何创建和使用Proxy,包括handler中的get和set方法。同时指出了Proxy解决的Vue2痛点,如对象属性监听不足,以及其存在的IE兼容性问题。

前言

vue3的 Proxy 最近貌似各大网红公众号都有发,我也来蹭蹭热度写一篇吧!我们也可以结合vue2来看看vue3到底发生了些什么变化,又解决了Vue2.x的哪些痛点。接下来我们一起看看~

目录结构

  • Proxy是什么?

    • 简单用法

  • 尝试案例

    • proxy - target 参数

  • Proxy - handler 参数

    • get()

    • set()

    • handler

  • 什么叫做数据双向绑定?

  • 简单实现数据渲染

  • Proxy实现双向绑定

  • 回顾 Vue2 双向绑定实现

  • Proxy 解决了Vue2的哪些痛点

  • Proxy 的缺陷

  • 延伸阅读

Proxy是什么?

Proxy 翻译过来就是代理的意思,何为代理呢?就是 用 new 创建一个目标对象(traget)的虚拟化对象,然后代理之后就可以拦截JavaScript引擎内部的底层对象操作;这些底层操作被拦截后会触发响应特定操作的陷阱函数。

简单用法
const p = new Proxy(target, handler)

target

要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler

一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

尝试案例

讲得再多,看得再多,不如写写再说 

Proxy - target 参数
// 定义一个空对象
let data = {};
// 创建一个 Proxy , 将 data 作为目标对象
let proxy = new Proxy(data, {});
// 修改Proxy 代理对象的name属性
proxy.name = '严老湿';
console.log(proxy); // { name: '严老湿' }
console.log(data); // { name: '严老湿' }

看了上面的案例,现在的你应该已经大概知道这个 Proxy 的目标对象(target)是怎么使用的了

Proxy  - handler 参数

handler 单独抽离出来作为一个大标题是因为里面的内容有点多

handler

handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。它里面的参数有太多了,我们就拿会用到几个讲讲吧!有像深究的同学可以去看看文档 Proxy handler [1]

参数 作用
handler.get() 属性读取操作的捕捉器。
handler.set() 属性设置操作的捕捉器。

handler.set

handler.set() 方法用于拦截设置属性值的操作。

文档上面呢基本上就是这样写的

// 定义一个对象
let data = {
  name: "严老湿",
  age: '24'
};
// handler 抽离出来
let handler = {
  set(target, prop, value) {
    console.log(target, prop, value)
  }
}
let p = new Proxy(data, handler);
p.age = 18;

个人习惯直接这样写

// 定义一个对象
let data = {
  name: "严老湿",
  age: '24'
};
// 创建一个 Proxy , 将 data 作为目标对象
let p = new Proxy(data, {
  set(target, prop, value) {
    // target = 目标对象
    // prop = 设置的属性
    // value = 修改后的值
    console.log(target, prop, value)
    // { name: '严老湿', age: '24' } 'age' 18
  }
});
// 直接修改p就可以了
p.age = 18;
console.log(data)
// { name: '严老湿', age: '24' }

在我们设置值的时候会触发里面的 set 方法;

我们已经捕捉到修改后的 属性 以及 他的值

但是打印data 并没有发生任何变化,那这还有啥用呢?

请看官方示例handler.set()[2]

在示例中出现了一个 Reflect.set()[3]

return Reflect.set(...arguments);

Reflect

Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API  [4]

我们需要在 handler.set()return 一个 Reflect.set(...argu

<think>好的,我现在需要帮助用户了解Vue3中h函数实现双向绑定的方法或原理。首先,我得回忆一下Vue3的相关知识,尤其是h函数和双向绑定的机制。 用户提供的引用内容提到了Vue3双向绑定主要基于Proxy和v-model,而h函数通常用于手写渲染函数。那么问题来了,h函数本身是否直接支持双向绑定,还是需要结合其他指令? 首先,h函数是用于创建虚拟节点的,它本身不处理数据绑定。在模板中,v-model会自动处理双向绑定,但在渲染函数中使用h函数时,需要手动设置属性和事件。例如,对于输入框,需要将value属性绑定到数据,并监听input事件来更新数据。 接下来,我需要验证这个思路是否正确。根据引用[2],v-model本质上是v-bind和v-on的语法糖。所以在h函数中,应该手动实现这两个部分。比如,给input元素设置value属性,并添加input事件监听器,在事件回调中更新数据。 然后,考虑到用户可能想知道具体的代码实现,我需要提供一个示例。比如使用reactive创建响应式对象,然后在h函数中为输入框设置value属性和onInput事件,事件中更新响应式数据。同时,需要说明Proxy在响应式系统中的作用,如引用[5]提到的Proxy实现数据劫持。 另外,需要区分vue2和vue3双向绑定差异,如引用[4]指出vue3使用Proxy,而vue2使用Object.defineProperty。这可能影响响应式系统的实现,但在h函数中手动绑定事件的方式是类似的,只是底层响应式原理不同。 最后,确保回答结构清晰,分步骤说明原理和实现方法,并附上代码示例。同时,生成相关问题,帮助用户进一步理解。</think>### Vue3中h函数实现双向绑定的原理及方法 在Vue3中,`h`函数是用于创建虚拟DOM节点的核心工具,常用于**自定义渲染函数**或**JSX语法**的场景。`h`函数本身并不直接提供双向绑定功能,但可以通过**手动绑定属性与事件**模拟双向数据流,其原理与模板中的`v-model`类似,需要结合Vue3的响应式系统实现[^1][^2][^5]。 --- ### 实现步骤 #### 1. 响应式数据绑定 Vue3的响应式系统基于`Proxy`实现数据劫持,通过`reactive`或`ref`创建响应式对象: ```javascript import { reactive } from &#39;vue&#39;; const state = reactive({ value: &#39;&#39; }); ``` #### 2. 手动绑定属性与事件 在`h`函数中,需要显式绑定`value`属性并监听输入事件(如`input`或`change`): ```javascript import { h } from &#39;vue&#39;; // 输入框组件示例 const InputComponent = { setup() { const state = reactive({ value: &#39;&#39; }); return () => h(&#39;input&#39;, { value: state.value, onInput: (e) => { state.value = e.target.value; // 更新数据 } }); } }; ``` #### 3. 实现双向同步 - **视图到数据**:通过事件监听(如`onInput`)更新响应式数据。 - **数据到视图**:依赖响应式系统自动触发视图更新[^1]。 --- ### 与`v-model`的关系 在模板中,`v-model`会自动编译为`value`属性和`@input`事件。而在`h`函数中,需手动实现这一过程: ```javascript // 等效于模板中的 <input v-model="state.value" /> h(&#39;input&#39;, { value: state.value, onInput: (e) => { state.value = e.target.value; } }); ``` --- ### 复杂组件示例(自定义组件) 对于自定义组件,需通过`props`和`emits`实现双向绑定: ```javascript const CustomInput = { props: [&#39;modelValue&#39;], emits: [&#39;update:modelValue&#39;], setup(props, { emit }) { return () => h(&#39;input&#39;, { value: props.modelValue, onInput: (e) => emit(&#39;update:modelValue&#39;, e.target.value) }); } }; // 父组件使用 h(CustomInput, { modelValue: state.value, &#39;onUpdate:modelValue&#39;: (val) => { state.value = val; } }); ``` --- ### 与Vue2的区别 Vue3使用`Proxy`实现响应式(引用[4][^4]),而Vue2使用`Object.defineProperty`。但`h`函数中手动绑定事件的方式在两者中是相似的。 --- ### 总结 - **核心原理**:通过`value`属性绑定数据 + 输入事件更新数据。 - **响应式依赖**:需结合`reactive`或`ref`实现数据变化到视图的自动同步[^5]。 - **灵活性**:手动绑定适用于复杂逻辑,但比模板语法更繁琐。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值