来自拉勾教育大前端训练营 vue 框架源码与进阶模块,以下内容为个人在学习过程中对响应式原理的总结~
先实现 mini 版 Vue 之前,我们先来了解一些概念
1、数据驱动
- 数据驱动
- 响应式的核心原理
- 发布订阅模式和观察者模式
数据驱动
- 数据响应式、双向绑定、数据驱动
- 数据响应式
- 数据模型仅仅是普通对象的 JavaScript,而我们修改数据时,视图会进行更新,避免了繁琐的 DOM 操作,提高开发效率
- 双向绑定
- 数据改变,视图改变,数据也随之改变
- 我们可以使用 v-model 在表单元素上创建双向数据绑定
数据驱动是 Vue 最独特的特性之一
- 开发过程中仅需要关注数据本身,不需要关系数据时如何渲染到视图
2、数据响应式的核心原理 Vue2
let data = {
msg: "大白菜",
};
// 模拟Vue的实例
let vm = {};
// 数据劫持, 当访问或者设置vm中成员的时候,做一些干预操作
Object.defineProperty(vm, "msg", {
// 可枚举
enumerable: true,
// 可配置 (可以使用delete杉树,也可通过defineProperty重新定义)
configurable: true,
get() {
return data.msg;
},
set(newValue) {
if (newValue === data.msg) {
return;
}
data.msg = newValue;
// 数据更改,更新DOM的值
document.querySelector("#app").textContent = data.msg;
},
});
// 测试
vm.msg = "Hello word";
console.log(vm.msg);
// 多个属性
let vm = {};
proxyData(data);
function proxyData(data) {
Object.keys(data).forEach((key) => {
Object.defineProperty(vm, key, {
enumerable: true,
configurable: true,
get() {
console.log("set:", key, data[key]);
return data[key];
},
set(newValue) {
if (newValue === data[key]) {
return;
}
data[key] = newValue;
document.querySelector("#app").textContent = data[key];
},
});
});
}
// vm.msg = '大白菜'
// set: msg 大白菜
3、Vue 响应式原理 Vue3
- MDN Proxy
- 直接监听对象, 而非属性
- ES6 中新增, IE 不支持,性能由浏览器优化
let data = {
msg: "hello",
};
let vm = new Proxy(data, {
get(target, key) {
return target[key];
},
// 设置vm的成员会执行
set(target, key, newValue) {
console.log("set", key, newValue);
if (target[key] === newValue) {
return;
}
target[key] = newValue;
document.querySelector("#app").textContent = target[key];
},
});
vm.msg = "大白菜";
console.log(vm.msg);
4、发布订阅模式
- 发布/订阅模式
- 订阅者
- 发布者
- 信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心“发布” (publish)一个信号,其他任务可以向信号中心“订阅” (subscribe)这个信号,从而知道什么时候自己可以开始执行,这就叫做“发布/定于模式” (publish-subscribe pattern)
let vm = new Vue();
// 注册事件(订阅消息)
vm.$on("dataChange", () => {
console.log("dataChange");
});
vm.$on("dataChange", () => {
console.log("dataChange1");
});
// 触发事件(发布消息)
// 自定义事件
class EventEmitter {
constructor() {
this.subs = Object.create(null);
}
// 注册事件
$on(eventType, handler) {
this.subs[eventType] = this.subs[eventType] || [];
this.subs[eventType].push(handler);
}
// 触发事件
$emit(eventType) {
if (this.subs[eventType]) {
this.subs[eventType].forEach((handler) => {
handler();
});
}
}
}
// 测试一下
let em = new EventEmitter();
em.$on("click", () => {
console.log("click1");
});
em.$on("click", function () {
console.log("click2");
});
em.$emit("click");
5、观察者模式
- 观察者(订阅者) -- Watcher
- upload(): 当事件发生时,