suchen
HeimWeb-FrontendView.jsIn diesem Artikel erhalten Sie eine detaillierte Analyse des Prinzips der bidirektionalen Bindung von Vue (verstehen Sie es gründlich).

Dieser Artikel passt ein Vue an und implementiert schrittweise die bidirektionale Bindung von Daten. Ich hoffe, dass er für alle hilfreich ist.

In diesem Artikel erhalten Sie eine detaillierte Analyse des Prinzips der bidirektionalen Bindung von Vue (verstehen Sie es gründlich).

Benutzerdefinierte Vue-Klasse

  • vue erfordert mindestens zwei Parameter: Vorlage und Daten. [Verwandte Empfehlungen: vue.js Video-Tutorial]

  • Erstellen Sie ein Compiler-Objekt, rendern Sie die Daten in die Vorlage und mounten Sie sie auf dem angegebenen Knoten.

class MyVue {
  // 1,接收两个参数:模板(根节点),和数据对象
  constructor(options) {
    // 保存模板,和数据对象
    if (this.isElement(options.el)) {
      this.$el = options.el;
    } else {
      this.$el = document.querySelector(options.el);
    }
    this.$data = options.data;
    // 2.根据模板和数据对象,渲染到根节点
    if (this.$el) {
      // 监听data所有属性的get/set
      new Observer(this.$data);
      new Compiler(this)
    }
  }
  // 判断是否是一个dom元素
  isElement(node) {
    return node.nodeType === 1;
  }
}

Realisieren Sie das erste Rendern von Daten auf der Seite.

Compiler die Seite auf einmal 2. Nachdem die Vorlage in den Speicher extrahiert wurde, verwenden Sie die buildTemplate-Funktion, um die Vorlagenelemente zu durchlaufen

Elementknoten

  • Verwenden Sie die buildElement-Funktion, um die Attribute zu überprüfen, die mit v- auf dem Element beginnen

    • Textknoten
  • Verwenden Sie buildText. Die Funktion prüft, ob der Text {{}} enthält

    • 3, erstellt die CompilerUtil-Klasse, die zur Verarbeitung von Vue-Anweisungen und {{}} verwendet wird. und schließt das Rendern der Daten ab
  • 4. Damit ist das erste Datenrendering abgeschlossen. Als nächstes müssen Sie die Ansicht automatisch aktualisieren, wenn sich die Daten ändern.
class Compiler {
  constructor(vm) {
    this.vm = vm;
    // 1.将网页上的元素放到内存中
    let fragment = this.node2fragment(this.vm.$el);
    // 2.利用指定的数据编译内存中的元素
    this.buildTemplate(fragment);
    // 3.将编译好的内容重新渲染会网页上
    this.vm.$el.appendChild(fragment);
  }
  node2fragment(app) {
    // 1.创建一个空的文档碎片对象
    let fragment = document.createDocumentFragment();
    // 2.编译循环取到每一个元素
    let node = app.firstChild;
    while (node) {
      // 注意点: 只要将元素添加到了文档碎片对象中, 那么这个元素就会自动从网页上消失
      fragment.appendChild(node);
      node = app.firstChild;
    }
    // 3.返回存储了所有元素的文档碎片对象
    return fragment;
  }
  buildTemplate(fragment) {
    let nodeList = [...fragment.childNodes];
    nodeList.forEach(node => {
      // 需要判断当前遍历到的节点是一个元素还是一个文本
      if (this.vm.isElement(node)) {
        // 元素节点
        this.buildElement(node);
        // 处理子元素
        this.buildTemplate(node);
      } else {
        // 文本节点
        this.buildText(node);
      }
    })
  }
  buildElement(node) {
    let attrs = [...node.attributes];
    attrs.forEach(attr => {
      // v-model="name" => {name:v-model  value:name}
      let { name, value } = attr;
      // v-model / v-html / v-text / v-xxx
      if (name.startsWith('v-')) {
        // v-model -> [v, model]
        let [_, directive] = name.split('-');
        CompilerUtil[directive](node, value, this.vm);
      }
    })
  }
  buildText(node) {
    let content = node.textContent;
    let reg = /\{\{.+?\}\}/gi;
    if (reg.test(content)) {
      CompilerUtil['content'](node, content, this.vm);
    }
  }
}
let CompilerUtil = {
  getValue(vm, value) {
    // 解析this.data.aaa.bbb.ccc这种属性
    return value.split('.').reduce((data, currentKey) => {
      return data[currentKey.trim()];
    }, vm.$data);
  },
  getContent(vm, value) {
    // 解析{{}}中的变量
    let reg = /\{\{(.+?)\}\}/gi;
    let val = value.replace(reg, (...args) => {
      return this.getValue(vm, args[1]);
    });
    return val;
  },
  // 解析v-model指令
  model: function (node, value, vm) {
    // 在触发getter之前,为dom创建Wather,并为Watcher.target赋值
    new Watcher(vm, value, (newValue, oldValue) => {
      node.value = newValue;
    });
    let val = this.getValue(vm, value);
    node.value = val;
  },
  // 解析v-html指令
  html: function (node, value, vm) {
    // 在触发getter之前,为dom创建Wather,并为Watcher.target赋值
    new Watcher(vm, value, (newValue, oldValue) => {
      node.innerHTML = newValue;
    });
    let val = this.getValue(vm, value);
    node.innerHTML = val;
  },
  // 解析v-text指令
  text: function (node, value, vm) {
    // 在触发getter之前,为dom创建Wather,并为Watcher.target赋值
    new Watcher(vm, value, (newValue, oldValue) => {
      node.innerText = newValue;
    });
    let val = this.getValue(vm, value);
    node.innerText = val;
  },
  // 解析{{}}中的变量
  content: function (node, value, vm) {
    let reg = /\{\{(.+?)\}\}/gi;
    let val = value.replace(reg, (...args) => {
      // 在触发getter之前,为dom创建Wather,并为Watcher.target赋值
      new Watcher(vm, args[1], (newValue, oldValue) => {
        node.textContent = this.getContent(vm, value);
      });
      return this.getValue(vm, args[1]);
    });
    node.textContent = val;
  }
}

Implementieren Sie die datengesteuerte Ansicht

Observer

1. Verwenden Sie die Funktion defineRecative, um die Object.defineProperty-Verarbeitung für die Daten durchzuführen, sodass alle Daten in den Daten durch get/set überwacht werden können2 Überlegen Sie als Nächstes, wie Sie den Ansichtsinhalt aktualisieren, nachdem Sie Änderungen im Datenwert abgehört haben. Erstellen Sie mithilfe des Observer-Entwurfsmusters die Klassen Dep und Water.

class Observer {
  constructor(data) {
    this.observer(data);
  }
  observer(obj) {
    if (obj && typeof obj === 'object') {
      // 遍历取出传入对象的所有属性, 给遍历到的属性都增加get/set方法
      for (let key in obj) {
        this.defineRecative(obj, key, obj[key])
      }
    }
  }
  // obj: 需要操作的对象
  // attr: 需要新增get/set方法的属性
  // value: 需要新增get/set方法属性的取值
  defineRecative(obj, attr, value) {
    // 如果属性的取值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
    this.observer(value);
    // 第三步: 将当前属性的所有观察者对象都放到当前属性的发布订阅对象中管理起来
    let dep = new Dep(); // 创建了属于当前属性的发布订阅对象
    Object.defineProperty(obj, attr, {
      get() {
        // 在这里收集依赖
        Dep.target && dep.addSub(Dep.target);
        return value;
      },
      set: (newValue) => {
        if (value !== newValue) {
          // 如果给属性赋值的新值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
          this.observer(newValue);
          value = newValue;
          dep.notify();
          console.log('监听到数据的变化');
        }
      }
    })
  }
}

Verwenden Sie das Beobachter-Entwurfsmuster, um die Dep- und Wather-Klassen zu erstellen.

1. Der Zweck der Verwendung des Beobachter-Entwurfsmusters besteht darin, die Vorlage zu analysieren und die in der Vorlage verwendeten Daten zu sammeln Bestimmte Daten werden in der Datensammlung des DOM-Knotens verwendet. Wenn sich die Daten ändern, wird durch Aktualisieren der DOM-Knotensammlung eine Datenaktualisierung realisiert.

Dep: wird verwendet, um die Sammlung von Dom-Knoten zu sammeln, von denen ein bestimmtes Datenattribut abhängt, und Aktualisierungsmethoden bereitzustellen.

  • Watcher: das Paketobjekt jedes Dom-Knotens.

  • attr: das Datenattribut, das von verwendet wird dom

    cb: Die Rückruffunktion, die den DOM-Wert ändert, erhält
    • 2, wenn sie erstellt wird. Zu diesem Zeitpunkt habe ich das Gefühl, dass die Idee in Ordnung ist, und ich bin bereits zuversichtlich, dass ich gewinnen werde. Wie nutzt man Dep und Watcher?
    • Fügen Sie für jedes Attribut eine Dep hinzu, um den abhängigen Dom zu sammeln

Da die Datendaten gelesen werden, wenn die Seite zum ersten Mal gerendert wird, und der Getter der Daten zu diesem Zeitpunkt ausgelöst wird, also Sammle den Dom hier

  • Wie sammle ich ihn konkret? Wenn die CompilerUtil-Klasse v-model, {{}} und andere Befehle analysiert, wird der Getter ausgelöst. Wir erstellen Water vor dem Auslösen und fügen dem Watcher ein statisches Attribut hinzu. Zeigen Sie auf den Dom und rufen Sie dann in der Getter-Funktion die statische Variable ab und fügen Sie sie der Abhängigkeit hinzu, um eine Sammlung zu vervollständigen. Da der statischen Variablen jedes Mal, wenn der Getter ausgelöst wird, ein Wert zugewiesen wird, kommt es nicht vor, dass falsche Abhängigkeiten erfasst werden.

  • class Dep {
      constructor() {
        // 这个数组就是专门用于管理某个属性所有的观察者对象的
        this.subs = [];
      }
      // 订阅观察的方法
      addSub(watcher) {
        this.subs.push(watcher);
      }
      // 发布订阅的方法
      notify() {
        this.subs.forEach(watcher => watcher.update());
      }
    }
    rrree

    3. An diesem Punkt wird die Ansicht automatisch aktualisiert, wenn Daten gebunden sind. Ursprünglich wollte ich den Code Schritt für Schritt implementieren, fand es aber schwierig, damit umzugehen, also habe ich die komplette Klasse gepostet.

  • Bei der Implementierung ansichtsgesteuerter Daten
  • werden tatsächlich die Eingabe- und Änderungsereignisse des Eingabefelds überwacht. Ändern Sie die Modellmethode von CompilerUtil. Der spezifische Code lautet wie folgt

    class Watcher {
      constructor(vm, attr, cb) {
        this.vm = vm;
        this.attr = attr;
        this.cb = cb;
        // 在创建观察者对象的时候就去获取当前的旧值
        this.oldValue = this.getOldValue();
      }
      getOldValue() {
        Dep.target = this;
        let oldValue = CompilerUtil.getValue(this.vm, this.attr);
        Dep.target = null;
        return oldValue;
      }
      // 定义一个更新的方法, 用于判断新值和旧值是否相同
      update() {
        let newValue = CompilerUtil.getValue(this.vm, this.attr);
        if (this.oldValue !== newValue) {
          this.cb(newValue, this.oldValue);
        }
      }
    }
  • Zusammenfassung

vue-Zwei-Wege-Bindungsprinzip

vue empfängt eine Vorlage und Datenparameter. 1. Durchlaufen Sie zunächst die Daten in Daten rekursiv, führen Sie Object.defineProperty für jede Eigenschaft aus und definieren Sie Get- und Set-Funktionen. Und fügen Sie für jede Eigenschaft ein Dep-Array hinzu. Wenn get ausgeführt wird, wird ein Watcher für den aufgerufenen DOM-Knoten erstellt und im Array gespeichert. Wenn set ausgeführt wird, wird der Wert neu zugewiesen und die notify-Methode des dep-Arrays aufgerufen, um alle Watcher zu benachrichtigen, die dieses Attribut verwenden, und den entsprechenden Dom-Inhalt zu aktualisieren. 2. Laden Sie die Vorlage in den Speicher, rekursieren Sie die Elemente in der Vorlage und stellen Sie fest, dass das Element einen Befehl hat, der mit v- oder einer doppelten Klammeranweisung beginnt. Der entsprechende Wert wird aus den Daten entnommen, um den Vorlageninhalt zu ändern Dieses Mal wird der Inhalt der Vorlage geändert. Das dom-Element wird zum dep-Array des Attributs hinzugefügt. Dadurch wird eine datengesteuerte Ansicht implementiert. Fügen Sie bei der Verarbeitung der V-Modell-Anweisung ein Eingabeereignis (oder eine Änderung) zum Dom hinzu und ändern Sie den Wert des entsprechenden Attributs bei der Eingabe, um seitengesteuerte Daten zu realisieren. 3. Nachdem Sie die Vorlage an die Daten gebunden haben, fügen Sie die Vorlage zum echten DOM-Baum hinzu.

Wie füge ich den Watcher in das Dep-Array ein? Beim Parsen der Vorlage wird der entsprechende Datenattributwert gemäß dem v-Befehl abgerufen. Zu diesem Zeitpunkt wird die get-Methode des Attributs aufgerufen. Wir erstellen zunächst eine Watcher-Instanz und rufen den darin enthaltenen Attributwert ab und speichern Sie es als alten Wert im Inside Watcher. Bevor wir den Wert erhalten, fügen wir das Attribut Watcher.target = this zum Watcher-Prototypobjekt hinzu und erhalten dann den Wert Watcher.target = null. Wenn get aufgerufen wird, kann es basierend auf dem Watcher-Instanzobjekt Watcher.target abgerufen werden.

Das Prinzip der Methoden

Beim Erstellen einer Vue-Instanz empfängt sie den Methodenparameter

und stößt beim Parsen der Vorlage auf die V-On-Anweisung. Dem dom-Element wird ein Listener für das entsprechende Ereignis hinzugefügt, und die Aufrufmethode wird verwendet, um Vue an diese Methode zu binden: vm.$methods[value].call(vm, e);

Prinzip der Berechnung

Wenn Sie eine Vue-Instanz erstellen, erhalten Sie den berechneten Parameter

Vue initialisieren Führen Sie während der Instanz eine Object.defineProperty-Verarbeitung für den berechneten Schlüssel durch und fügen Sie das get-Attribut hinzu.

(Lernvideo-Sharing: Web-Frontend)

Das obige ist der detaillierte Inhalt vonIn diesem Artikel erhalten Sie eine detaillierte Analyse des Prinzips der bidirektionalen Bindung von Vue (verstehen Sie es gründlich).. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme
Dieser Artikel ist reproduziert unter:掘金社区. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen
VUE.JS: Definieren seiner Rolle in der WebentwicklungVUE.JS: Definieren seiner Rolle in der WebentwicklungApr 18, 2025 am 12:07 AM

Vue.js 'Rolle in der Webentwicklung besteht darin, als progressives JavaScript -Framework zu fungieren, das den Entwicklungsprozess vereinfacht und die Effizienz verbessert. 1) Es ermöglicht Entwicklern, sich auf Geschäftslogik durch reaktionsschnelle Datenbindung und Komponentenentwicklung zu konzentrieren. 2) Das Arbeitsprinzip von Vue.js beruht auf reaktionsschnellen Systemen und virtuellem DOM, um die Leistung zu optimieren. 3) In den tatsächlichen Projekten ist es üblich, Vuex zu verwenden, um den globalen Zustand zu verwalten und die Datenreaktionsfähigkeit zu optimieren.

Vue.js verstehen: vor allem ein Frontend -FrameworkVue.js verstehen: vor allem ein Frontend -FrameworkApr 17, 2025 am 12:20 AM

Vue.js ist ein progressives JavaScript -Framework, das von Ihnen Yuxi im Jahr 2014 veröffentlicht wurde, um eine Benutzeroberfläche zu erstellen. Zu den Kernvorteilen gehören: 1. Responsive Datenbindung, automatische Aktualisierungsansicht von Datenänderungen; 2. Komponentenentwicklung kann die Benutzeroberfläche in unabhängige und wiederverwendbare Komponenten aufgeteilt werden.

Netflix -Frontend: Beispiele und Anwendungen von React (oder Vue)Netflix -Frontend: Beispiele und Anwendungen von React (oder Vue)Apr 16, 2025 am 12:08 AM

Netflix verwendet React als Front-End-Framework. 1) Reacts komponentiertes Entwicklungsmodell und ein starkes Ökosystem sind die Hauptgründe, warum Netflix es ausgewählt hat. 2) Durch die Komponentierung spaltet Netflix komplexe Schnittstellen in überschaubare Teile wie Videotiere, Empfehlungslisten und Benutzerkommentare auf. 3) Die virtuelle DOM- und Komponentenlebenszyklus von React optimiert die Rendering -Effizienz und die Verwaltung des Benutzerinteraktion.

Die Frontend -Landschaft: Wie Netflix ihre Auswahl annähteDie Frontend -Landschaft: Wie Netflix ihre Auswahl annähteApr 15, 2025 am 12:13 AM

Die Auswahl von Netflix in der Front-End-Technologie konzentriert sich hauptsächlich auf drei Aspekte: Leistungsoptimierung, Skalierbarkeit und Benutzererfahrung. 1. Leistungsoptimierung: Netflix wählte React als Hauptgerüst und entwickelte Tools wie SpeedCurve und Boomerang, um die Benutzererfahrung zu überwachen und zu optimieren. 2. Skalierbarkeit: Sie übernehmen eine Mikro-Front-End-Architektur, die Anwendungen in unabhängige Module aufteilt und die Entwicklungseffizienz und die Systemskalierbarkeit verbessern. 3. Benutzererfahrung: Netflix verwendet die Material-UI-Komponentenbibliothek, um die Schnittstelle kontinuierlich durch A/B-Tests und Benutzer-Feedback zu optimieren, um Konsistenz und Ästhetik sicherzustellen.

React vs. Vue: Welches Framework verwendet Netflix?React vs. Vue: Welches Framework verwendet Netflix?Apr 14, 2025 am 12:19 AM

NetflixuSesacustomframeworkcalted "Gibbon" Builtonreact, NotreactorVuedirect.1) TeamExperience: Wählen Sie beobädtes Vertrauen

Die Wahl der Frameworks: Was treibt die Entscheidungen von Netflix vor?Die Wahl der Frameworks: Was treibt die Entscheidungen von Netflix vor?Apr 13, 2025 am 12:05 AM

Netflix berücksichtigt hauptsächlich Leistung, Skalierbarkeit, Entwicklungseffizienz, Ökosystem, technische Schulden und Wartungskosten bei der Rahmenauswahl. 1. Leistung und Skalierbarkeit: Java und Springboot werden ausgewählt, um massive Daten und hohe gleichzeitige Anforderungen effizient zu verarbeiten. 2. Entwicklungseffizienz und Ökosystem: Verwenden Sie React, um die Effizienz der Front-End-Entwicklung zu verbessern und sein reiches Ökosystem zu nutzen. 3. Technische Schulden- und Wartungskosten: Wählen Sie Node.js, um Microservices zu erstellen, um Wartungskosten und technische Schulden zu senken.

Reagieren, Vue und die Zukunft von Netflix 'FrontendReagieren, Vue und die Zukunft von Netflix 'FrontendApr 12, 2025 am 12:12 AM

Netflix verwendet React hauptsächlich als Front-End-Framework, das durch VUE für bestimmte Funktionen ergänzt wird. 1) Die Komponentierung von React und das virtuelle DOM verbessern die Leistung und Entwicklungseffizienz von Netflix -Anwendungen. 2) VUE wird in den internen Tools und kleinen Projekten von Netflix verwendet, und seine Flexibilität und Benutzerfreundlichkeit sind entscheidend.

Vue.js im Frontend: Anwendungen und Beispiele in realer WeltVue.js im Frontend: Anwendungen und Beispiele in realer WeltApr 11, 2025 am 12:12 AM

Vue.js ist ein progressives JavaScript -Framework, das zum Erstellen komplexer Benutzeroberflächen geeignet ist. 1) Zu seinen Kernkonzepten gehören Reaktionsdaten, Komponentierungen und virtuelle DOM. 2) In praktischen Anwendungen kann es durch den Aufbau von Todo -Anwendungen und die Integration von Vuerouter demonstriert werden. 3) Beim Debuggen wird empfohlen, VODEVTOOLS und CONSOLE.LOG zu verwenden. 4) Die Leistungsoptimierung kann durch V-IF/V-Show, Listen-Rendering-Optimierung, asynchrone Belastung von Komponenten usw. erreicht werden.

See all articles

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
1 Monate vorBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
1 Monate vorBy尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Crossplay haben?
1 Monate vorBy尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

SecLists

SecLists

SecLists ist der ultimative Begleiter für Sicherheitstester. Dabei handelt es sich um eine Sammlung verschiedener Arten von Listen, die häufig bei Sicherheitsbewertungen verwendet werden, an einem Ort. SecLists trägt dazu bei, Sicherheitstests effizienter und produktiver zu gestalten, indem es bequem alle Listen bereitstellt, die ein Sicherheitstester benötigen könnte. Zu den Listentypen gehören Benutzernamen, Passwörter, URLs, Fuzzing-Payloads, Muster für vertrauliche Daten, Web-Shells und mehr. Der Tester kann dieses Repository einfach auf einen neuen Testcomputer übertragen und hat dann Zugriff auf alle Arten von Listen, die er benötigt.

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Herunterladen der Mac-Version des Atom-Editors

Herunterladen der Mac-Version des Atom-Editors

Der beliebteste Open-Source-Editor

MinGW – Minimalistisches GNU für Windows

MinGW – Minimalistisches GNU für Windows

Dieses Projekt wird derzeit auf osdn.net/projects/mingw migriert. Sie können uns dort weiterhin folgen. MinGW: Eine native Windows-Portierung der GNU Compiler Collection (GCC), frei verteilbare Importbibliotheken und Header-Dateien zum Erstellen nativer Windows-Anwendungen, einschließlich Erweiterungen der MSVC-Laufzeit zur Unterstützung der C99-Funktionalität. Die gesamte MinGW-Software kann auf 64-Bit-Windows-Plattformen ausgeführt werden.