文章目录
一、Vue2
1.基本原理
在vue2中利用的是原生js下的Obiect.defineProperty()
进行数据劫持,在通过里面的getter
和setter
方法,进行查看和数据的修改,通过发布、订阅者模式进行数据与视图的响应式
2.定义初始数据
3.加工数据
为了实现响应式,在js中Object.defineProperty()
给每个初始数据都形成了get和set的写法,只要读取数据就会执行get方法,编辑数据执行set方法。
(1)响应式数据
(2)get查看age属性,执行get
(3)set修改数据的时候调用set
(4)总结
当数据发生变化时,触发响应的监听回调(get/set),就已经实现了数据的双向绑定
4.vue双向绑定的缺点
(1)不能监听对象的新增属性和删除
(2)无法正确的监听数组的方法,当监听下标对应的数据发生变化时
5.解决办法
(1)重写数组或对象
(2)vue中通过this.$set(目前属性,新增的属性,新增的值)来解决
二、Vue3
1.基本原理
(1)对于基本数据类型来说,响应式依然是靠Object.defineProperty()的get和set来完成的
(2)对于对象类型数据:
- 通过Proxy代理,拦截对象中任意属性的变化,包括属性值的读写、添加、删除等
- 通过Reflect反射函数进行操作
Vue3中响应式是通过函数来实现的
2.ref函数
(1)作用:定义一个响应式数据
(2)语法:let xxx=ref(xxx)
(3)创建一个包含响应式数据的引用对象
(4)js中操作数据:xxx.value
(5)模板中读取数据:不需要.value直接使用插值语法即可
(6)注:接收的数据可以是基本类型也可以是对象类型
3.reactive函数
(1)作用:定义一个对象类型的响应式数据
(2)语法:const xxx=reactive(源对象)接收一个数组或者对象,返回一个Proxy的实例对象,简称Proxy
返回proxy对象
(3)reactive定义的响应式的数据是深层次的
(4)接受的是数组,通过索引改变的数据也是响应式的
三、Vue的响应式原理基于的核心概念:
(1)Observer
:Vue使用Observer来监控数据的变化,一旦数据变化,就触发视图更新。
(2)Dep
:每个数据属性都有一个Wep依赖管理器,它记录依赖于这个属性的所有Watcher。
(3)Watcher
:每个组件实例都有相应的Watcher,它会在组件渲染过程中“观察”数据的变化。
(4)Virtual DOM
:Vue使用Virtual DOM来高效地更新DOM。
(5) Diff算法
当数据变化时,新旧Virtual DOM会进行Diff算法对比差异,然后只更新有差异的部分
// 假设的Vue响应式核心代码
class Vue {
constructor(options) {
this._data = options.data;
observe(this._data, this); // 监控数据
new Compiler(options.el, this); // 编译模板,并生成Watcher
}
}
function observe(data, vm) {
if (!data || typeof data !== 'object') {
return;
}
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key], vm); // 对每个数据属性进行响应式处理
});
}
function defineReactive(obj, key, val, vm) {
const dep = new Dep();
// 获取属性的Descriptor
const property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return;
}
// 使用getter和setter重写属性
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
dep.addSub(Dep.target); // 添加依赖
return val;
},
set: function reactiveSetter(newVal) {
if (val === newVal) return;
val = newVal;
dep.notify(); // 通知依赖更新
}
});
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => {
sub.update(); // 执行更新操作
});
}
}
// 假设的Watcher类
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.expOrFn = expOrFn;
this.cb = cb;
this.value = this.get(); // 获取初始值,同时订阅依赖
}
get() {
Dep.target = this; // 设置当前Watcher为target
const value = this.vm._data[this.expOrFn]; // 触发属性的getter
Dep.target = null; // 重置
return value;
}
update() {
const newValue = this.vm._data[this.expOrFn];
if (newValue !== this.value) {
this.cb.call(this.vm, newValue); // 执行更新回调
}
}
}
// 假设的Compiler类
class Compiler {
constructor(el, vm) {
this.el = document.querySelector(el);
this.vm = vm;
if (this.el) {
const fragment = this.nodeToFragment(this.el);
this.compile(fragment);
this.el.appendChild(fragment);
}
}
nodeToFragment(el) {
// 将DOM转换为Fragment的实现
}
compile(fragment) {