好家伙,狠狠地补一下代码量
本篇我们来尝试使用原生js实现vue的响应式
使用原生js,即代表没有v-bind,v-on,也没有v-model,所有语法糖我们都用原生实现
1.给输入框绑个变量
<body>
<input id="input_1"></input>
</body>
<script>
let datavalue = "66666"
const input_1 = document.getElementById("input_1")
input_1.value = datavalue
input_1.addEventListener('input', function(e) {
datavalue = e.target.value
console.log(datavalue)
})
</script>
诶,似乎这样就完成了
但我们要让他更像vue
2.加上Dep,Watcher
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="input_1"></input>
</body>
<script>
// 模拟 Vue 实例
let data = {
message: 'Hello'
};
const input_1 = document.getElementById("input_1")
input_1.value = data.message
input_1.addEventListener('input', function (e) {
e.target.value = data.message
console.log(datavalue)
})
function defineReactive(obj, key, value) {
let dep = new Dep(); // 依赖容器
Object.defineProperty(obj, key, {
get: function () {
if (Dep.target) {
dep.addDep(Dep.target);
}
return value;
},
set: function (newValue) {
value = newValue;
dep.notify();
}
});
}
// 依赖容器
function Dep() {
this.deps = [];
this.addDep = function (dep) {
this.deps.push(dep);
};
this.notify = function () {
this.deps.forEach(dep => {
dep.update();
});
};
}
Dep.target = null;
// Watcher
function Watcher(updateFunc) {
this.update = updateFunc;
}
// 初始化响应式数据
defineReactive(data, 'message', data.message);
// 模拟 Watcher
let watcher = new Watcher(function () {
console.log('Message updated:', data.message);
input_1.value = data.message
});
// 模拟视图更新
Dep.target = watcher;
data.message; // 触发依赖收集
setTimeout(() => {
data.message = '6666'; //触发更新
}, 1000)
</script>
</html>
3.效果图
4.代码解释
-
defineReactive
函数用来定义一个响应式属性,其中通过Object.defineProperty
给属性添加 getter 和 setter 方法。在 getter 方法中,会判断Dep.target
是否存在,如果存在则将当前 Watcher 对象添加到依赖容器 Dep 中;在 setter 方法中,更新属性的值,并通过依赖容器 Dep 的notify
方法通知所有依赖的 Watcher 进行更新。 -
Dep
函数是一个简单的依赖容器,其中包含了一个 deps 数组用来存储依赖(Watcher),addDep
方法用来添加依赖,notify
方法用来通知所有依赖进行更新。 -
Watcher
函数用来创建 Watcher 对象,其中包含一个update
方法,用来在属性发生变化时执行相应的更新操作。 -
在初始化响应式数据时,调用
defineReactive
函数定义了一个名为message
的响应式属性。 -
创建了一个 Watcher 对象
watcher
,并在其构造函数中定义了一个回调函数,用来在属性变化时输出消息并更新视图。 -
将
watcher
赋值给Dep.target
,然后访问data.message
,触发依赖收集,将watcher
添加到依赖容器 Dep 中。
5.补充
一张响应式原理图