In der täglichen Entwicklung ist
$set
auch eine sehr praktische API, da der Kern der Reaktionsfähigkeit von Vue2 darin besteht, dieObject.defineProperty
von ES5 zu verwenden Array oder fügen Sie dem Objekt neue Eigenschaften hinzu, indem Sie den Array-Index direkt ändern. Object.defineproperty kann die Datenänderungen zu diesem Zeitpunkt nicht überwachen, sodass jeder$set
verwendet, sodass die geänderte Operation auch die Antwort implementiert. Wir wissen es, aber auch warum. Schauen wir uns als Nächstes an, wie $set in Vue implementiert wird. [Verwandte Empfehlungen: vuejs-Video-Tutorial$set
的也是一个非常实用的API,因为Vue2实现响应式的核心是利用了ES5的Object.defineProperty
,当我们通过直接修改数组下标更改数组或者给对象添加新的属性,这个时候Object.defineproperty是监听不到数据的变化的,这时候大家就会用上$set
,让修改的操作也实现响应,我们知其然更要知其所以然,接下来看一下Vue中的$set是如何实现的。【相关推荐:vuejs视频教程、web前端开发】
let dataArr = ["item1"]; let dataObject = { name: "ccs" }; dataArr[2] = "item2"; dataObject.age = 22; 响应失败,页面没有显示更新新增的数据 this.$set(this.dataArr,2,'item2') this.$set(this.dataObject,'age',22) 响应成功,页面显示更新新增的数据
接下来我们看一下$set在Vue中的定义
function set(target: Array<any> | Object, key: any, val: any): any { if ( process.env.NODE_ENV !== "production" && (isUndef(target) || isPrimitive(target)) ) { warn( `Cannot set reactive property on undefined, null, or primitive value: ${(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 && !(key in Object.prototype)) { target[key] = val; return val; } const ob = (target: any).__ob__; if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== "production" && warn( "Avoid adding reactive properties to a Vue instance or its root $data " + "at runtime - declare it upfront in the data option." ); return val; } if (!ob) { target[key] = val; return val; } defineReactive(ob.value, key, val); ob.dep.notify(); return val; }
在源码中首先判断set的目标是否是undefined
和基本类型
如果是undefined
或基本类型
就报错,
因为用户不应该往undefined和基本类型中set东西,
然后又判断了目标是否是数组与key是不是合法的index,合法的index是指值为大于等于0的整数,
如果两个条件都成立就对目标数组调用splice方法插入或者修改数组
,
这里的splice
不是普通的splice
,是王维诗里的splice,是被vue代理重写过的splice
$set实现数组修改响应的方式是代理重写的数组的一部分方法,接下来我们看一下具体实现
const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto) const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] function def(obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true }); } methodsToPatch.forEach(function (method) { const original = arrayProto[method] def(arrayMethods, method, function mutator (...args) { const result = original.apply(this, args) const ob = this.__ob__ let inserted switch (method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } if (inserted) ob.observeArray(inserted) ob.dep.notify() return result }) })
vue中代理重写的不只是splice
,有push、pop、shift、unshift、splice、sort、reverse
这七个方法,
首先执行了const result = original.apply(this, args)
执行原本数组的方法并获取它的值,接下来判断如果是往数组中添加值就将新添加的值也实现响应式
,
最后一步拿到这个数组的_ob_对象
对_ob_
里的dep进行派发更新。
想深入了解vue的响应式可以查阅往期文章
面试官问你Vue2的响应式原理,你怎么答? - 掘金 (juejin.cn)
$set
中下半部分的逻辑就是用来处理对象响应的,我们接着往下看
if (key in target && !(key in Object.prototype)) { target[key] = val; return val; } const ob = (target: any).__ob__; if (!ob) { target[key] = val; return val; } defineReactive(ob.value, key, val); ob.dep.notify(); return val;
首先判断了属性如果在目标对象中直接return结束逻辑,
因为vue只有添加目标对象中原本没有的属性时才会失去响应,例如 let obj={} obj.name='ccs'
,
vue在初始化的时候会将data里的所有属性都变成响应式,如果的值是对象或者数组则会new一个Observer
实例储存在__ob__,想深入了解vue的响应式可以查阅往期文章
面试官问你Vue2的响应式原理,你怎么答? - 掘金 (juejin.cn)
拿到这个对象的_ob_进行判断,如果不存在就说明是未经过vue初始化的普通对象而不是响应式对象否则就手动通过defineReactive
为属性添加get方法与set方法实现响应,
然后手动调用dep
里的notify()
, Web-Frontend-Entwicklung
splice
, es gibt sieben Methoden: Push, Pop, Shift , verschieben, spleißen, sortieren, umkehren.
Zuerst führt const result = original.apply(this, args)
die Methode des ursprünglichen Arrays aus und erhält seinen Wert und bestimmt dann, ob er dem Array hinzugefügt wird Durch das Hinzufügen eines Werts wird die Reaktionsfähigkeit
des neu hinzugefügten Werts erkannt. _ob_-Objekt ab array.code>Verteilen und aktualisieren Sie die Abhängigkeit in <code>_ob_
. $set
Die Logik in der unteren Hälfte wird verwendet, um Objekte reaktionsfähig zu verarbeiten Schauen wir weiter nach unten.🎜rrreee🎜Zunächst beurteilen wir, ob das Attribut direkt im Zielobjekt zurückgegeben wird, um die Logik zu beenden,Beispiel: let obj={} obj.name='ccs'
,Observer
-Instanz in __ob__ gespeichert. Wenn Sie mehr über die Reaktionsfähigkeit von Vue erfahren möchten, können Sie sich die vorherigen ansehen ArtikeldefineReactive
zum Attribut hinzu, um die Antwort zu implementieren, dep <code>notify()
veröffentlicht Updates. 🎜🎜Zusammenfassung🎜🎜Die $set-Methode in vue behandelt Arrays und Objekte im Wesentlichen auf die gleiche Weise. Sie fügt eine Antwort auf den neuen Wert hinzu und löst dann manuell die Versandaktualisierung aus. 🎜🎜 (Teilen von Lernvideos: 🎜Vuejs-Einführungs-Tutorial🎜, 🎜Grundlegendes Programmiervideo🎜)🎜
Das obige ist der detaillierte Inhalt vonLassen Sie uns darüber sprechen, wie $set in Vue implementiert wird.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!