Heim  >  Artikel  >  Web-Frontend  >  Lassen Sie uns darüber sprechen, wie $set in Vue implementiert wird.

Lassen Sie uns darüber sprechen, wie $set in Vue implementiert wird.

青灯夜游
青灯夜游nach vorne
2022-12-15 21:26:322991Durchsuche

Lassen Sie uns darüber sprechen, wie $set in Vue implementiert wird.

In der täglichen Entwicklung ist $set auch eine sehr praktische API, da der Kern der Reaktionsfähigkeit von Vue2 darin besteht, die Object.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实现

接下来我们看一下$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 = [
  &#39;push&#39;,
  &#39;pop&#39;,
  &#39;shift&#39;,
  &#39;unshift&#39;,
  &#39;splice&#39;,
  &#39;sort&#39;,
  &#39;reverse&#39;
]
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 &#39;push&#39;:
      case &#39;unshift&#39;:
        inserted = args
        break
      case &#39;splice&#39;:
        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

]

Anwendungsszenarien

rrreee

set-Implementierung

Als nächstes werfen wir einen Blick auf die Definition von $set in Vue

rrreeeBestimmen Sie im Quellcode zunächst, ob das Ziel von set ist undefiniert und Basistyp Wenn es sich um undefiniert oder Basistyp handelt, wird ein Fehler gemeldet,
Da der Benutzer keine undefinierten und grundlegenden Typen festlegen sollte, wird beurteilt, ob das Ziel ein Array ist und ob der Schlüssel ein zulässiger Index ist, der auf eine Ganzzahl mit einem Wert verweist größer oder gleich 0.
Wenn beide Bedingungen wahr sind, rufen Sie die Splice-Methode für das Zielarray auf, um das Array einzufügen oder zu ändern,
das Splice Code> hier ist kein gewöhnlicher <code>Spleiß, ist ein Spleiß in Wang Weis Gedicht, das ein Spleiß ist strong>das vom Vue-Proxy neu geschrieben wurde

Array-Implementierung Antwort Die Art und Weise, wie $set das Array implementiert, um die Antwort zu ändern, ist Teil des Arrays Als nächstes werfen wir einen Blick auf die spezifische Implementierungrrreee🎜vue Das Umschreiben des Proxys ist nicht nur 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.
Der letzte Schritt ruft das _ob_-Objekt ab array.code>Verteilen und aktualisieren Sie die Abhängigkeit in <code>_ob_.
Wenn Sie mehr über die Reaktionsfähigkeit von Vue erfahren möchten, können Sie sich frühere Artikel ansehen.
Der Interviewer hat Sie nach dem Reaktionsfähigkeitsprinzip von Vue2 gefragt. Wie haben Sie geantwortet? - Nuggets (juejin.cn) 🎜🎜

Objektimplementierungsantwort 🎜🎜$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,
Da Vue nur Attribute hinzufügt, die ursprünglich nicht vorhanden sind im Zielobjekt. Antwortverlust,
Beispiel: let obj={} obj.name='ccs',
vue ändert alle Attribute in Daten während der Initialisierung Werden reaktionsfähig. Wenn der Wert ein Objekt oder Array ist, wird eine neue Observer-Instanz in __ob__ gespeichert. Wenn Sie mehr über die Reaktionsfähigkeit von Vue erfahren möchten, können Sie sich die vorherigen ansehen Artikel
Der Interviewer hat Sie nach Vue2 gefragt. Wie antworten Sie auf das Prinzip der Reaktionsfähigkeit? - Nuggets (juejin.cn)🎜
Erhalten Sie das _ob_ dieses Objekts zur Beurteilung. Wenn es nicht existiert, bedeutet dies, dass es sich um ein gewöhnliches Objekt handelt, das nicht von vue initialisiert wurde und kein Antwortobjekt ist /strong> Andernfalls fügen Sie die get-Methode und die set-Methode manuell über defineReactive zum Attribut hinzu, um die Antwort zu implementieren,
und rufen Sie dann 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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen