包教包会!Vue3源码之响应式原理(二)

书接上回

追踪多个属性

课程链接:www.vuemastery.com/courses/vue...

追踪一个属性需要一个Set对象,那么追踪多个属性,就需要多个Set对象,这些对象也需要一个地方存放,这个地方同样需要满足两个要求:

  • 能遍历;
  • 值是键值对,这样才能对应key值存对应的相关依赖。

Map对象刚好满足上述条件。可以新建一个Map对象,追踪多个响应式属性。

js 复制代码
// ...
// 1、不在此处新建set对象了
// const dep = new Set();
 ​
// 2、新建多个属性的依赖收集对象
const depsMap = new Map();
 ​
// 3、修改依赖追踪函数,从Map中读取对应属性,若无则新建该属性对应的set对象并加进Map中,之后为该属性添加effect
const track = (key) => {
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  dep.add(effect);
};
​
// 4、修改依赖触发执行函数,从depsMap中读取对应属性的依赖并遍历执行
const trigger = (key) => {
  const dep = depsMap.get(key);
  if (dep) {
     dep.forEach((effect) => effect());
  }
};
 ​
effect();
track('quantity');
track('price');
console.log(total); // --> 10
​
product.quantity = 3;
trigger('quantity');
console.log(total); // --> 15
​
product.price = 6;
trigger('price');
console.log(total); // --> 18

总结

  • dep的基础上拔高一层,新增Map对象,存放每个属性对应的dep对象,从而追踪多个属性。

问题

  • 依赖的收集和effect的触发依然需要手动执行。
  • 追踪多个属性,还不能追踪对象。

追踪对象

既然当前能追踪多个属性了,而对象是由多个属性组成,那可以继续拔高一层,将多个属性的追踪变成对象的追踪。

js 复制代码
const product = { price: 5, quantity: 2 };
let total = 0;
let effect = () => (total = product.price * product.quantity);
// 1.不在此处追踪多个属性了
// const depsMap = new Map();
// 2.新建targetMap,追踪对象的属性,注意这里可以用WeakMap,因为存放的是对象
const targetMap = new WeakMap();
 ​
// 3.1修改依赖追踪函数,从Map中读取对应对象,若无则新建该对象对应的map对象并加进Map中
// 3.2 之后的逻辑同追踪多个属性的逻辑
const track = (target, key) => {
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  dep.add(effect);
};
 ​
 // 4、修改依赖触发执行函数,从targetMap中读取对应对象,再在对象里读取对应属性的依赖并遍历执行
const trigger = (target, key) => {
  const depsMap = targetMap.get(target);
  if (depsMap) {
  const dep = depsMap.get(key);
  if (dep) {
    dep.forEach((effect) => effect());
  }
}
};
 ​
effect();
track(product, 'quantity');
track(product, 'price');
console.log(total); // --> 10
​
product.quantity = 3;
trigger(product, 'quantity');
console.log(total); // --> 15
​
product.price = 6;
trigger(product, 'price');
console.log(total); // --> 18

总结

  • 新增targetMap结构存放对象的相关依赖,targetMap存的对象的值是depsMap对象,depsMap里才是存放对应属性的相关依赖。

问题

  • 依赖的收集和effect的触发依然需要手动执行。
相关推荐
一 乐4 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
小御姐@stella4 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
万叶学编程7 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
积水成江10 小时前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
计算机学姐10 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
老华带你飞11 小时前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计
qbbmnnnnnn11 小时前
【WebGis开发 - Cesium】如何确保Cesium场景加载完毕
前端·javascript·vue.js·gis·cesium·webgis·三维可视化开发
杨荧12 小时前
【JAVA开源】基于Vue和SpringBoot的水果购物网站
java·开发语言·vue.js·spring boot·spring cloud·开源
霸王蟹13 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
老章学编程i14 小时前
Vue工程化开发
开发语言·前端·javascript·vue.js·前端框架