手机版

分析vue 设置()和这个 $set()来自Vue源代码

时间:2021-08-30 来源:互联网 编辑:宝哥软件园 浏览:

前言

最近,我对vue源代码痴迷了一段时间。我想我还是需要输出一些东西。让我们首先看看它是如何从两个APIs Vue.set()和这个内部实现的。$set()由VUE提供。

Vue.set()和这个的场景。$set()应用程序

通常在做项目的时候,不可避免的是数组或者对象不会受到这样的骚操作。结果发现,嘿~ ~,他喵喵,为什么页面没有重新渲染?

const vueininstance=new Vue({ data : { arr :[1,2],obj 1: { a : 3 } } });vueininstance。$ data . arr[0]=3;//这种操作页面不会重新渲染vueInstance。$ data . obj 1 . b=3;//这种骚操作页面不会重新渲染。我查了一下官方文件,发现很早以前就有人说过这种情况

Vue.set()向响应对象添加一个属性,并确保新属性也是响应的并触发视图更新。它必须用于向响应对象添加新属性,因为Vue无法检测普通的新属性(例如this.myObject.newProperty='hi ')

因此,根据官网的写法,我们应该采用以下写法:

vue . set(vueininstance。$data.arr,0,3);//这个操作数组可以让页面重新呈现vueinstance。$ set(vueininstance。$ data.arr,0,3);//以这种方式操作数组也可以使页面重新呈现vue . set(vueininstance。$ data.obj1,b,3);//这样,操作对象可以使页面重新呈现vueinstance。$ set(vueininstance。$ data.obj1,b,3);//这样操作对象也可以让页面重新呈现Vue.set()和这个的原理。$set()

是时候看看这两个API的源代码了。我们先来看看Vue.set()的源代码:

从“”导入{set}.“观察者/索引”.vue。set=set.让我们看看这个的源代码。$set():

从“”导入{set}.“观察者/索引”.vue.prototype. $ set=set.结果,我们发现Vue.set()的实现原理和这个一样。设置功能从导出./observer/index文件,区别在于Vue.set()将set函数绑定到Vue构造函数,而这。$set()将set函数绑定到Vue原型。

然后我们根据下列公式求出集合函数./观察者/索引:

函数集(target: Arrayany | Object,key: any,val : any): any { if(process . ENV . NODE _ ENV!==' production '(isUndef(target)| | isPrimitive(target))){ warn(`无法对未定义、null或基元值设置reactive属性: $ {(target : any)} `)} if(array . isarray(target)isValidArrayIndex(key)){ target . length=math . max(target . length,key) target.splice(key,1,val) return val } if (key in target!(Object.prototype中的键){ target[key]=val return val } const ob=(target : any)。__ob__ if(目标。_ isVue | |(ob . vmcount)){ process . ENV . NODE _ ENV!=='production' warn('避免在运行时向Vue实例或其根$data ' '添加反应性属性-在数据选项中提前声明它。')返回val } if(!Ob) {target [key]=val returnval}定义reactive (ob。值、键、值)ob。离开notify () returnval}我们发现set函数接收三个参数,分别是target、key和val,其中target的值是数组或者对象,对应的是调用官网给出的Vue.set()方法时传入的参数如下图所示:

我们接着往下看:

if (process.env.NODE_ENV!==' production '(isUndef(target)| | isPrimitive(target)){ warn(`无法在未定义、null或isPrimitive值: $ {(target : any)} `)上设置reactive属性}让我们首先看一下isUndef和is primitive方法。从名字可以看出,isUndef是判断target等于undefined还是null。IsPrimitive是判断目标的数据类型是字符串、数字、符号还是布尔值。因此,如果当前环境不是生产环境,并且isundef(目标)| | isprimary(目标)为真,则将引发错误警告。

数组的实现原理

然后往下看:

if(array . isarray(target)is validarayindex(key)){ target . length=math . max(target . length,key) target.splice(key,1,Val) return val}这实际上是允许我们在修改数组时调用set方法时触发响应的代码,但是在分析这段代码之前,让我们先看看vue中的数组实际是什么样子。下图是vue和普通js数组中的数组:

vue中的数组名为arrVue,js中的常用数组名为arrJs。实际上,我们通常调用的普通array的push、pop等方法都是在被调用的Array原型上面定义的方法。从图中我们可以看到,arrjs的原型指向Array.prototype,意思是arrJs。_ _ proto _ _==array.prototype.

然而,在vue的数组中,我们发现arrVue的原型不是Array.prototype,而是一个对象(我们在这里将这个对象命名为arrayMethods)。ArrayMethods上只有7个push、pop等方法,arrayMethods的原型是指Array.prototype,所以我们在vue中调用array的push、pop等方法时,直接调用的不是array prototype提供的push、pop等方法,而是被调用的arrayMethods提供的push、pop等方法。为什么vue将这种数组方法添加到数组的原型链中?这里涉及到vue的数据响应原理,暂时不讨论数据响应原理的具体实现。在这里,你可以理解为vue在arrayMethods对象中做了特殊处理。如果调用arrayMethods提供的push、pop等七种方法,会触发当前收集的依赖项(暂时可以理解为呈现函数),导致页面重新呈现。换句话说,对于数组的操作,只有arrayMethods提供的七种方法会导致页面呈现,这也解释了为什么我们使用vueInstance。$ data . arr[0]=3;不会导致页面呈现。

弄清楚vue中的数组是如何实现的之后,让我们看看上面的代码:

If(数组。isarray(target)is validarrayindex(key)){ target。长度=数学。最大(目标。长度、键)目标。split (key,1,val) return val}首先,if确定当前目标是否为数组,key的值是否为有效的数组索引。然后将目标数组的长度设置为target.length和key的最大值。你为什么要在这里做这个?这是因为我们可能会执行以下操作:

arr1=[1,3];Vue.set(arr1,10,1) //如果不这样做,这种情况就会出错。向下看,我们发现target.split (key,1,val)在这里被直接调用。我们之前说过,调用arrayMethods提供的push和pop等七种方法会导致页面重新呈现。拼接只是属性arrayMethods提供的七种方法之一。

总结一下Vue.set数组实现的原理:其实Vue.set()实际上是调用拼接方法进行数组处理的。你觉得很简单吗~ ~

对象的实现原理

接下来让我们看看代码:

if(键入目标!(键入对象。prototype){ target[key]=val return val }这里,首先判断key是否是对象中的属性,key是否不是对象原型上的属性。说明该键已经在对象上定义,因此您可以直接修改该值并自动触发响应。

我们不详细解释对象依赖集合和触发器的原理,但你可以暂时理解。Vue使用Object.defineProperty来截取对象。当触发get时,会收集依赖项(这里收集的依赖项被理解为类似数组的呈现函数),当触发set时,会触发依赖项,导致呈现函数执行页面重新呈现。那么你第一次触发是从哪里来的呢?实际上,它是在第一次加载页面呈现时触发的。这里将进行递归来收集对象的属性,所以当我们修改对象的现有属性值时,页面将被重新呈现。这正好解释了为什么我们使用vueInstance。$ data . obj 1 . b=3;为什么页面不会重新渲染,因为这里的属性b不是对象的已有属性,也就是说属性b还没有收集到依赖,所以修改属性b的值就不会重新渲染页面。

接下来让我们看看代码:

const ob=(target: any)。__ob__ if(目标。_ isVue | |(ob . vmcount)){ process . ENV . NODE _ ENV!=='production' warn('避免在运行时向Vue实例或其根$data ' '添加反应性属性-在数据选项中提前声明它。')返回val } if(!Ob) {target[key]=val return val}首先,定义变量Ob的值为target。__ob__。这个__ob__属性是什么对象?Vue向所有响应对象添加__ob__属性。如果一个对象有这个__ob__属性,说明这个对象是有响应的,当我们修改这个对象的现有属性时,就会触发页面呈现。

目标。_ isVue | |(ob . vmcount)表示如果当前目标对象是Vue实例对象或根数据对象,将引发错误警告。

if(!Ob)为真,表示当前目标对象不是响应对象,所以可以直接赋值返回。

然后往下看:

定义反应性。值、键、值)ob。离开notify()返回val这是vue.set()真正处理对象的地方。定义反应性。value、key、val)意味着向新添加的属性添加依赖关系,这将在将来直接修改新属性时触发页面呈现。

代码ob.dep.notify()意味着触发当前的依赖关系(这里的依赖关系仍然可以理解为一个呈现函数),因此页面将被重新呈现。

摘要

从源代码层面来看,两个API(vue . set()和这个。vue提供的$set())仍然非常简单。由于本文没有详细说明Vue依赖于采集和触发,有些地方还是比较模糊的。

以上就是对vue源代码Vue.set()和这个的分析。$set()由边肖推出。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

版权声明:分析vue 设置()和这个 $set()来自Vue源代码是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。