大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript
等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter
等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js
进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。
技术qq交流群:906392632
大家好,我是小杨,一个写了6年前端的老兵。
今天咱们聊聊Vue里一个让人直呼"神奇"的特性------双向数据绑定。你有没有想过,为什么在Vue里改个数据,页面就自动更新了?反过来,页面输入框一输入,数据也跟着变?这背后的原理是啥?
作为面试常考题,很多人能背出"通过Object.defineProperty或Proxy实现",但具体怎么运作的?为啥能实时同步?今天我就用最直白的方式拆解它,保证你听完恍然大悟!
一、什么是双向绑定?
先看个经典例子:
html
<template>
<input v-model="myText" />
<p>{{ myText }}</p>
</template>
<script>
export default {
data() {
return {
myText: 'Hello!' // 我在data里定义了一个变量
}
}
}
</script>
- 效果 :输入框里打字,下面的
<p>
标签内容实时同步。 - 本质 :数据(
myText
)和视图(input框、p标签)双向联动。
二、单向绑定 vs 双向绑定
- 单向绑定 :数据变 → 视图更新(比如React的
state
)。 - 双向绑定 :数据变 ⇄ 视图更新(Vue的
v-model
)。
关键问题:Vue怎么做到"数据变,视图就变"?
三、核心原理:数据劫持 + 发布订阅
Vue通过以下两步实现双向绑定:
1. 数据劫持(观察数据变化)
Vue会遍历data里的所有属性,用Object.defineProperty
(Vue2)或Proxy
(Vue3)给每个属性加上"监听":
js
// 简化版数据劫持逻辑(Vue2风格)
function defineReactive(obj, key) {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
console.log(`读取了${key}:${value}`)
return value
},
set(newVal) {
if (newVal !== value) {
console.log(`修改了${key}:${newVal}`)
value = newVal
// 触发视图更新(后面讲)
}
}
})
}
// 对我的data对象进行劫持
const myData = { text: 'Hello' }
defineReactive(myData, 'text')
myData.text = 'Hi!' // 控制台输出:修改了text:Hi!
- 效果 :只要修改
myData.text
,就会被set
函数捕获到。
2. 依赖收集与视图更新
光知道数据变了还不够,还得找到哪些视图依赖了这个数据。Vue的做法是:
- Step 1 :在编译模板时,遇到
{{ myText }}
或v-model
,就创建一个Watcher(监听器)。 - Step 2 :Watcher在读取数据时触发
get
,把自身"订阅"到这个数据的变化上。 - Step 3 :数据变化时,通过
set
通知所有订阅它的Watcher,Watcher再去更新视图。
(这个过程类似"发布-订阅"模式,数据是发布者,Watcher是订阅者。)
四、v-model 的本质
双向绑定的语法糖v-model
,实际上等于:
html
<input
:value="myText"
@input="myText = $event.target.value"
/>
:value
:数据 → 视图(单向绑定)@input
:视图 → 数据(事件监听)
五、Vue3的升级:Proxy
Vue2用Object.defineProperty
有个缺陷:无法监听新增属性(比如obj.newKey = xxx
)。
Vue3改用Proxy
,直接劫持整个对象:
js
const myData = { text: 'Hello' }
const proxy = new Proxy(myData, {
set(target, key, value) {
target[key] = value
console.log(`修改了${key}:${value}`)
return true
}
})
proxy.text = 'Hi!' // 生效
proxy.newKey = 123 // 同样生效!
六、手写极简双向绑定
为了加深理解,咱们手写一个丐版双向绑定:
html
<input id="input" />
<p id="text"></p>
<script>
const myData = {}
const input = document.getElementById('input')
const text = document.getElementById('text')
// 数据劫持
Object.defineProperty(myData, 'value', {
set(val) {
input.value = val
text.innerText = val
},
get() {
return input.value
}
})
// 视图 → 数据
input.addEventListener('input', (e) => {
myData.value = e.target.value
})
// 测试
myData.value = 'Hello!'
</script>
- 效果:输入框和文本会同步变化,虽然简陋,但原理相通。
七、总结
- Vue2 通过
Object.defineProperty
劫持数据,Vue3改用Proxy
。 - 依赖收集:Watcher在getter中订阅数据变化。
- 派发更新:setter时通知所有Watcher更新视图。
- v-model 本质是
:value + @input
的语法糖。
双向绑定不是魔法,而是精妙的设计!
最后:如果你在面试中被问到这个问题,可以分三步回答:
- 数据劫持(怎么监听变化)
- 依赖收集(怎么知道更新谁)
- 派发更新(怎么触发更新)
觉得有用的话,点个赞吧~ 有疑问欢迎评论区交流!