携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
数组,一直是我在vue中使用最多的数据结构,当我们使用v-for的时候,对应的数据也基本是一个数组,因此代理数组在vue中很重要,今天我们就跟随作者,一起来了看看如何代理数组。
在我们之前曾经讲过:常规对象和异质对象,并且说数组是最常见的异质对象.我们对比一下数组的特殊之处。
- 通过下标读取和修改值,
arr[0]=1 arr.length时返回数组的长度,修改arr.length会导致数据的变化- 可以使用
for ... in和for...of遍历 - 原型链上自带很多方法,比如
filter、slice、push、shift,其中有改变自身的,也有不改变的
从这四点可以看出,数组与对象差别还是蛮大的,但是对于我们写的代码,其实差别并不是很大,因为数组也只是一个对象而已,我们之前写的代码还是可以复用大部分的。
首先我们先看一下如何响应数组下标的变化。我们给数组中不存在的元素赋值,那就是新增,反正就只是更新。
比如arr.lenght = 2;arr[2] = 2,在判断数组类型上,我直接使用es6的新API,Array.isArray.
const TriggerType = { SET:'SET', ADD:'ADD', DEL:'DELETE' }
const createReactive = (obj,deepify = true, onlyRead=false)=>new Proxy(obj,{
set(target,key,newVal,receiver){
/*省略其他逻辑*/
const type = Array.isArray(target)
? Number(key)<target.length ? TriggerType.SET : TriggerType.ADD
: Object.prototype.hasOwnProperty.call(target,key) ? TriggerType.SET :TriggerType.ADD
}
/*省略其他拦截*/
})
这样我们就实现了,对数组赋值的响应。但是,数组中还有一个特殊的length属性需要处理。在追踪的时候我们无需修改,仍将它当作一个普通的属性去处理。
const trigger = (target,key,type)=>{
/*省略其他逻辑*/
if(type === TriggerType.ADD && Array.isArray(target)){
const lengthEffects = depsMap.get('length')
lengthEffects&& lengthEffects.forEach(fn=>fn!==activeEffect?effectToRun.add(fn):'')
}
}
当我们修改length的时候,并不意味着需要响应数组中所有的元素,我们应当只响应大于等于新length的元素。
所以我们需要将新的length传进去,在trigger中进行判断。在触发响应的时候,我们能拿到新的length值,这时候将它传入trigger作为对比。
//新增newVal这个参数
const trigger = (target,key,type,newVal)=>{
/*省略其他逻辑*/
if(Array.isArray(target) && key === 'length'){
depsMap.forEach((fns,key)=>{
if(key>=newVal){
fns.forEach(fn=>fn!==activeEffect?effectToRun.add(fn):'')
}
})
}
}
我们为trigger增加了第四个参数,newVal就是新的length值,它表示数组的长度发生了变化。当我们触发响应式,如果数据是数组,则找到所有下标大于等于新length值的元素,再执行与他们相关的副作用函数。
下一章我们开始讲数组的遍历,这也是数组中比较重要的一部分。