问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

【源码解析】看看$set是如何添加响应式属性的

发布网友 发布时间:2024-09-06 11:19

我来回答

1个回答

热心网友 时间:2024-11-06 09:13

前言

大家好,上一篇文章MVVM中我们共同学习了Vue2中MVVM的原理,并用一个极其简单的案例模拟实现了一下mvvm的基本流程。今天我们将继续学习一下vue2中$set方法的源码及原理。在分析源码之前我们先来看下这个$set方法是干嘛用的,为什么要有这么个方法存在。

案例

大家都知道:响应式是vue中最大的特点之一,就比如说当我们把data中定义的某个属性(name)值修改后,对应的用到该属性(name)的页面上也会同步更新,同样也可以通过页面上的表单元素进行反向修改(即修改了表单元素的值,对应的绑定的属性name也会同步更新)。

但是这种情况也是有条件的,前提就是该属性必须已经提前定义在data中了。

还有另外一种情况,我们用一个案例来模拟一下:比如在data中定义一个obj对象,该对象包含一个name属性,然后再将该对象通过小胡子语法显示在页面上,那么毫无疑问这个name属性肯定是响应式的双向都可以修改,如下代码和效果图:

<divid="app">obj:{{obj}}</div>constvm=newVue({el:"#app",data:{obj:{name:"Alvin"}}});

?现在又来了个新需求:要求我们通过点击一个按钮动态为obj对象再添加一个age属性,看上去好像也挺简单,就是在页面上添加一个按钮并绑定一个click事件,然后再在绑定的事件中给obj添加一个age属性即可,如下:

<button@click="addAge">addage</button>constvm=newVue({methods:{addAge(){this.obj.age=18;}}});

然而,当我们把代码运行起来发现点击按钮却没有任何反应,貌似age属性没有添加成功,然后打开控制台发现实际上age已经添加进去了,但却不是响应式的(没有三个点)也就是说虽然age添加成功了但却没有被劫持因此也就不能双向绑定了。如下图:

这是因为vue仅在初始化的时候对已经定义了的属性只进行一次数据劫持,后面再添加的属性就不再进行劫持了,这也正是为什么age属性添加成功了但却不是响应式的原因。

那么如果我们就是想要动态添加一个响应式的属性就没办法了吗,当然不是的。为了解决这个问题vue为我们提供了一个额外的专门用来添加响应式属性的方法$set,也就是本次我们要分享的核心(铺垫了这么多主人公终于出场了)。下面我们把this.obj.age=18改成用$set的形式添加再来看下效果:

addAge(){//该方法接收3个参数:第一个是要添加属性的对象,第二个是要添加的属性名,第三个参数属性值this.$set(this.obj,'age',18);}

这样修改后我们再来看新添加的age属性就已经显示在页面上了。

$set源码

通过上面的案例我们知道通过$set我们可以添加一个响应是的属性,那么它的实现原理是什么呢,下面我们通过$set的源码来解读一下:下载到vue2的源码后找到src/core/instance/observer/index.js文件,在该文件中有如下代码片段就是$set的源码,一共30来行看上去还是比较简单的。

//该方法接收三个参数,target:要添加属性的对象,key:属性名,val:属性值functionset(target,key,val){//首先判断target不能是undefine,null或原始值,如果是这三者之一则抛出错误if(isUndef(target)||isPrimitive(target)){warn(("Cannotsetreactivepropertyonundefined,null,orprimitivevalue:"+((target))));}//判读target是否是一个数组,如果是数组并且key是一个一个有效索引则进行单独处理,//vue2中数组和对象的数据劫持的实现方式不同if(Array.isArray(target)&&isValidArrayIndex(key)){target.length=Math.max(target.length,key);target.splice(key,1,val);//通过数组的splice方法添加一个新值returnval}//如果要添加的属性已经在对象中存在并且不是对象的原生属性,则直接进行赋值操作if(keyintarget&&!(keyinObject.prototype)){target[key]=val;returnval}//__ob__是vue中的内置属性,包括dep、value和vmCount三个值,//其中dep就是我们前面分享mvvm时的Dep的实例用来做依赖收集和通知模板更新的,//而value的值其实就是传进来的targetvarob=(target).__ob__;if(target._isVue||(ob&&ob.vmCount)){warn('AvoidaddingreactivepropertiestoaVueinstanceoritsroot$data'+'atruntime-declareitupfrontinthedataoption.');returnval}//如果ob不存在,则直接做赋值操作if(!ob){target[key]=val;returnval}//接下来则是$set函数实现添加响应式属性的核心代码,同样这个方法在我们分享mvvm时也已经分析过了,//该方法接收三个参数,ob.value上面我们说了其实就是target用于添加响应式属性的对象,//key是要添加的响应式属性的名称,val则是对应属性的值。在该方法内容通过原生的Object.property方法//对属性进行数据劫持,并通过dep.depend方法进行依赖收集defineReactive$$1(ob.value,key,val);//然后通过dep实例中的notify方法通知视图更新ob.dep.notify();returnval}总结

今天的分享我们通过一个简单案例分析学习了如果给对象添加一个响应式属性,从而引出了vue中的$set方法,并通过对$set源码的分析我们知道了$set的实现原理,知道了为什么$set就可以添加响应式属性。好了,本次分享就到这里了。

原文:https://juejin.cn/post/7101847136685260837
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
什么样的胶水能粘铝水箱上 什么是破产犯罪 现行刑法对故意销毁会计账簿罪立案是怎么规定的 如果很讨厌一个人,要怎么发泄 讨厌一个人,要怎么礼貌的告诉他?如题 谢谢了 耿直的人,为什么适合质检部? 黄易群侠传副本任务分别在那领 cad图层怎么用(autocad图层怎么用) AUTOCAD中的图层有什么作用,怎样使用啊! AutoCAD怎样使用图层? 深入Dify 源码,洞察 Dify RAG 核心机制 如何用django网站源码(2023年最新解答) UMI3源码解析系列之构建原理 低代码页面搭建平台在百瓶的实践 【源码解析】了解了MVVM的原理后我自己也写了个MVVM mk源码是什么意思? 干货!TAPD编辑器完整使用攻略 Mermaid的流程图基本用法 ……但……一写一句话 用“司空见惯”、“本想”、“但”、“便”、“然后”写一句话 战略合作伙伴和合作伙伴有什么区别 全天候全面战略伙伴关系有哪些国家 南瓜紫米粥有什么营养价值? 记得三角形的三条边分别为abc请化简代数式。I a十b一cI一la一b一Cl... 高压吸尘器多少钱 总结UF盖板的优点 数字经济对企业转型的影响有哪些 结婚伴手礼什么时候送 结婚伴手礼一般给什么 如何把空间的相片批量导出到电脑上? ...青少年犯罪的条款 ,17岁的孩子故意伤人,在法律上能受到惩罚吗_百度... excel文件怎么无法转换为dat格式excel文件不能转换成的文件有 华鬘介绍 经常吃泡面没吃饭对身体有什么影响么?如题 谢谢了 紧急避孕药2片怎么吃 素质报告书学生自我评价怎么写 六个字霸气经典短句? 关于立冬故事 公安刑警哪个专业 欧派和雅迪品质哪个好 ...词语造句.学富五车 满腹经纶 学贯中西 博古通今 功成名就 著作等... 2022济南融创水世界门票多少钱一张 附最新优惠门票价格 济南水上乐园有哪些地方 牙疼快一个月了,吃药没用,有什么好的办法吗 请问我是由牙疼引起的,已经快一个月了,现在我的牙齿经牙医转洞来减压... 牙疼一个月了,每时每刻都在胀痛,一敲更疼不敢咬,冷热水不怕,请问是牙髓... 交投逸景天宸和观湖园哪个好 武汉交投逸景天宸开发商是? ...成都这几个城市中的某一个工作,它在拉萨的东边, 米加小镇怎么玩? - 知乎 任城区行政区划