前言
今天来聊聊vue2中的响应式数据的原理,究竟是如何去实现双向绑定的?
什么是响应式?
我们都知道Vue是一个MVVM的模式,在 MVVM 模式中,有三个核心组件:
- Model:
- 表示应用程序的数据模型和业务逻辑。
- 它是应用程序的核心,与用户界面无关。
- View:
- 表示用户界面。
- 它是Model中数据的可视化展现。
- ViewModel:
- 扮演Model和View之间的桥梁角色。
- ViewModel负责把Model的数据同步到View上,并将View上的数据变化同步回Model。
- ViewModel完全封装了View和Model之间的交互细节,使得开发者无需关注这些细节。
响应式就是
- 当用户在视图组件中修改数据时,数据模型中的相应数据会自动更新。
- 当数据模型中的数据发生变化时,视图组件也会自动更新以反映这些变化。
Object.defineProperty
Object.defineProperty()可以实现属性的数据劫持
<span id="container">1</span>
<button id="btn">加一</button>
<script>
const btn = document.querySelector("#btn");
const span = document.querySelector("#container");
btn.addEventListener("click", () => {
span.innerHTML = parseInt(span.innerHTML) + 1;
});
</script>
以上代码实现了当我点击按钮就可以为数字添加一的效果
但是我们观察这段代码可以发现,这段代码没有将视图和数据进行分离
每一次点击按钮都是去主动的操控了dom元素
接下来我们修改代码
<span id="container">1</span>
<button id="btn">加一</button>
<script>
const btn = document.getElementById("btn");
const span = document.getElementById("container");
var obj = {
value: 1,
};
var value = 1;
btn.addEventListener("click", () => {
obj.value++;
console.log(obj.value);
});
// 监控对象 es5
Object.defineProperty(obj, "value", {
get: function () {
return value;
},
set: function (newValue) {
value = newValue;
console.log("值改变了");
// 更新视图
span.innerHTML = value;
},
});
</script>
使用 Object.defineProperty() 方法实现简单的数据响应式
-
首先定义一个
obj对象,其value属性初始值为 1。 -
然后通过
document.getElementById()获取页面上的<span>元素和<button>元素。 -
为
<button>元素添加一个 click 事件监听器。当按钮被点击时,会触发obj.value的自增操作,并打印出新的值。 -
接下来,使用
Object.defineProperty()方法对obj.value属性进行数据劫持。- 定义
get函数,返回当前value的值。 - 定义
set函数,在值发生变化时更新<span>元素的内容。
- 定义
这样,当用户点击按钮时,obj.value 的值会发生变化,通过 set 函数中的逻辑,页面上的 <span> 元素也会随之更新,实现了简单的数据双向绑定。
我们继续修改代码
<span id="cintainer">1</span>
<span id="txt">hi</span>
<button id="btn">加一</button>
<button id="btn2">点击</button>
<script>
var obj = {
value: 1,
txt: "hi",
};
(function () {
function watch(obj, key, func) {
console.log("监听任何要监听的数据");
var value = obj[key];
Object.defineProperty(obj, key, {
get: function () {
return value;
},
set: function (newValue) {
value = newValue;
func(newValue);
},
});
}
this.watch = watch;
})();
// 数据可以被监听
watch(obj, "value", function (newValue) {
document.getElementById("cintainer").innerHTML = newValue;
});
watch(obj, "text", function (newValue) {
document.getElementById("txt").innerHTML = newValue;
});
document.getElementById("btn").addEventListener("click", function () {
obj.value++;
});
document.getElementById("btn2").addEventListener("click", function () {
obj.text = "哈哈哈";
});
</script>
这段代码展示了如何通过自定义一个 watch 函数来实现对对象属性的监听和数据双向绑定。
主要流程如下:
-
定义一个立即执行函数,在其内部定义了
watch函数。 -
watch函数接受三个参数:obj: 需要被监听的对象key: 需要被监听的对象属性func: 当属性值发生变化时要执行的回调函数
-
在
watch函数内部,首先记录当前属性的值。 -
然后使用
Object.defineProperty()对该属性进行数据劫持:get函数返回当前属性值set函数在属性值发生变化时执行传入的回调函数func
-
在主逻辑中,分别对
obj的"value"和"text"属性使用watch函数进行监听,并在回调函数中更新相应的 DOM 元素。 -
为两个按钮添加点击事件监听器,分别触发
obj.value和obj.text的变化。
通过这种自定义 watch 函数的方式,我们可以轻松地对任意对象的任意属性进行监听和数据绑定,并在属性值发生变化时执行相应的更新逻辑。这方式与 Vue.js 中的数据响应式机制非常相似,体现了同样的设计思想。
总结
本文讲解了Vue2响应式数据原理之Object.defineProperty,希望对你能够有所帮助