Fassen Sie sieben Kommunikationsmethoden zwischen Vue-Komponenten zusammen

Während des Entwicklungsprozesses werden Sie immer auf verschiedene Kommunikationssituationen zwischen Komponenten stoßen. Allerdings gibt es in Vue viele Möglichkeiten, zwischen Komponenten zu kommunizieren. Heute habe ich eine kleine Zusammenfassung erstellt. Als nächstes werfen wir einen Blick auf die Kommunikationsmethoden:

1. Requisiten / $emit

Dies ist eine der Methoden, die wir normalerweise häufiger verwenden. Die übergeordnete Komponente A übergibt Daten über Props-Parameter an die untergeordnete Komponente. Die untergeordnete Komponente sendet über $emit ein Ereignis (mit Parameterdaten) an die übergeordnete Komponente. Die übergeordnete Komponente hört auf $ emittieren und auslösen Das Ereignis ruft die von der untergeordneten Komponente an sich selbst gesendeten Daten ab.

Hier ist ohne weiteres ein einfaches Beispiel:

Code der übergeordneten Komponente:

<template>
  <div>
    <p>我是父组件</p>
    <!-- 通过props把值传给子组件 -->
    <son
     :text-from-father="text"
     @tell-father="tellMe"
    />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son,
  }
})
 
export default class father extends Vue {
  text:string = '我是父组件';
 
  执行子组件触发的事件
  tellMe(val: string) {
    //接受到子组件传过来的值
    console.log(val); //I am son
  }
}
</script>

Unterkomponentencode:

<template>
  <div>
    <p>我是子组件</p>
    <div>父组件告诉我:{
   
   {textFromFather}}</div>
    <el-button @click="tellFather">发送文字给父组件</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import {EventBus} from './event-bus.js'
 
@Component({
  name: 'son',
  components: {
  }
})
 
export default class son extends Vue {
  @Prop({
    default: ''
  })
  textFromFather !: string; //设置props属性值,得到父组件传递过来的数据
 
  tellFather() {
    //触发父组件中的事件,向父组件传值
    this.$emit('tell-father','I am son')
  }
}
 
</script>

Die übergeordnete Komponente übergibt Daten an die untergeordnete Komponente und bindet über v-on ein Tell-Father-Ereignis, um auf das Auslöseereignis der untergeordneten Komponente zu warten.

Die Unterkomponente erhält die relevanten Textdaten über Requisiten und löst schließlich das Tell-Father-Ereignis aus.$emit um die Kommunikation abzuschließen.

 

二、$children / $parent

Offizielle Einführung von $children: direkte untergeordnete Komponenten der aktuellen Instanz. Beachten Sie, dass $children weder die Reihenfolge garantiert noch reagiert.

 

Offizielle Einführung von $parent: Die übergeordnete Instanz der aktuellen Instanz.

 

Der über $children erhaltene Wert ist ein Array, das eine Sammlung direkter untergeordneter Elemente darstellt. In Bezug auf den spezifischen Sohn gibt es im Sohn ein _uid-Attribut. Sie können wissen, um welches Element es sich handelt, und dies ist die eindeutige Kennung des Elements. $ parent ist ein Objekt.

 

Nachdem Sie nun die Instanz der Komponente erhalten haben, können Sie die Eigenschaften oder Methoden der Komponente aufrufen, um sie auszuführen.

 

Als nächstes schauen wir uns an, wie der Code die Kommunikation implementiert:

Code der übergeordneten Komponente:

<template>
  <div>
    <p>我是父组件</p>
    <children />
    <el-button @click="changeChildren">点击改变子组件值</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import children from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    children
  }
})
 
export default class father extends Vue {
  msg: string = '父组件传过来的msg'
 
  changeChildren() {
    console.log(this.$children) //所有子组件,打印的是一个数组
 
    //找到children组件,改变属性值
    this.$children[0].messageA = 'this is new value from father'
 
    //调用children的方法
    this.$children[0].getName('daming');  //my name is daming
  }
 
}
</script>

Unterkomponentencode:

<template>
  <div>
    <p>我是子组件</p>
    <p>{
   
   {messageA}}</p>
    <p>获取父组件的值为:{
   
   {parentVal}}</p>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
 
@Component({
  name: 'children',
  components: {
     
  }
})
 
export default class father extends Vue {
  messageA: string = 'this is old'
 
  get parentVal(){
    return this.$parent.msg;//拿到父组件传过来的值
  }
 
  getName(name: string) {
    console.log(`my name is ${name}`)
  }
}
</script>

Nach dem Abrufen der Instanz kann die übergeordnete Komponente mithilfe der Methoden der untergeordneten Komponente die Eigenschaften der untergeordneten Komponente direkt ändern. Auf die gleiche Weise können untergeordnete Komponenten auch direkt die Eigenschaften und Methoden der übergeordneten Komponenten verwenden.

Hinweis: Sie müssen auf Randbedingungen achten. Wenn Sie beispielsweise $parent für #app verwenden, erhalten Sie eine Instanz von new Vue(). Wenn Sie $parent für diese Instanz verwenden, erhalten Sie undefiniert, und if Wenn Sie $children für die unterste untergeordnete Komponente verwenden, ist diese leer. Array.

Wenn die übergeordnete Komponente jedoch eine Attributfreigabe gemeinsam nutzen muss, müssen alle ihre untergeordneten Elemente auf das Freigabeattribut zugreifen. In diesem Fall kann die untergeordnete Komponente über this.$parent.share auf die Freigabe zugreifen.

Allerdings sind nach diesem Muster erstellte Komponenten immer noch anfällig für interne Probleme. Beispielsweise verschachteln wir eine Unterkomponente „children2“ innerhalb der Unterkomponente, etwa:

<template>
  <div>
    <p>我是父组件</p>
    <children>
        <children2>
    <children/>
  </div>
</template>
 

Wenn Sie dann auf die Freigabe in der Komponente „Children2“ zugreifen, müssen Sie zunächst prüfen, ob die Freigabe in der übergeordneten Komponente vorhanden ist. Wenn sie nicht vorhanden ist, suchen Sie eine Ebene höher danach und implementieren Sie sie im Code:

var share = this.$parent.share || this.$parent.$parent.share;

Dadurch gerät die Komponente schnell außer Kontrolle: Das Erreichen der übergeordneten Komponente erschwert das Debuggen und Verstehen der Anwendung, insbesondere wenn die Daten der übergeordneten Komponente geändert werden. Nach einer Weile ist es schwierig herauszufinden, wo die Änderung initiiert wurde.

Daher eignen sich $children und $parent besser für die Kommunikation zwischen Eltern-Kind-Komponenten.

Zusammenfassung: Die beiden oben genannten Methoden werden für die Kommunikation zwischen übergeordneten und untergeordneten Komponenten verwendet. Die offizielle Empfehlung lautet, Requisiten für die Kommunikation zwischen übergeordneten und untergeordneten Komponenten zu verwenden.

 

3. Ref/Ref

ref: Bei Verwendung auf einem normalen DOM-Element zeigt die Referenz auf das DOM-Element; bei Verwendung auf einer Unterkomponente zeigt die Referenz auf die Komponenteninstanz, über die die Methoden der Komponente direkt aufgerufen oder auf Daten zugegriffen werden kann.

Beispiel:

Code der übergeordneten Komponente:

<template>
  <div>
    <p>我是父组件</p>
    <son ref="mySon" />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son
  }
})
 
export default class father extends Vue {
  mounted() {
    const mySon: any = this.$refs.mySon;
    console.log(mySon.name) //lingling
    mySon.sayHello(); //hello, I am son
  }
}
</script>

 

Unterkomponentencode:

<template>
  <div>
    <p>我是儿子组件</p>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Inject } from "vue-property-decorator";
 
@Component({
  name: 'son',
  components: {
     
  }
})
 
export default class son extends Vue {
  name: string = 'lingling'
  sayHello () {
    console.log('hello, I am son')
  }
}
 
</script>

 

4. Vuex

Vuex ist ein Zustandsverwaltungsmodell, das einen zentralen Speicher verwendet, um den Zustand aller Komponenten der Anwendung zu verwalten, und entsprechende Regeln verwendet, um sicherzustellen, dass sich der Zustand auf vorhersehbare Weise ändert.

Der Kern der Vuex-Anwendung ist der Store (Lager, ein Container). Der Store enthält den größten Teil des Status Ihrer Anwendung;

Jeder Status des Vuex-Moduls
: Wird zur Datenspeicherung verwendet und ist die einzige Datenquelle im Speicher.
Getter: Wie die berechneten Eigenschaften in Vue, basierend auf der sekundären Verpackung von Statusdaten, häufig zur Datenfilterung und Korrelationsberechnung mehrerer Daten verwendet.
Mutationen : Ähnlich wie Funktionen, die einzige Möglichkeit, Statusdaten zu ändern, und kann nicht zur Behandlung asynchroner Ereignisse verwendet werden;
Aktionen: Ähnlich wie Mutationen, wird verwendet, um Mutationen zu übermitteln, um den Status zu ändern, ohne den Status direkt zu ändern, und kann alle asynchronen Vorgänge umfassen;
Module : ähnlich Im Namespace wird es im Projekt verwendet, um den Status jedes Moduls separat zu definieren und zu verwalten, um die Wartung zu erleichtern;

Vuex implementiert einen unidirektionalen Datenfluss und verfügt über einen Status zum globalen Speichern von Daten. Wenn eine Komponente die Daten im Status ändern möchte, muss dies über Mutation erfolgen. Mutation bietet auch einen Abonnentenmodus für den Aufruf externer Plug-Ins Erhalten Sie Aktualisierungen der Staatsdaten. Wenn alle asynchronen Vorgänge oder synchronen Batch-Vorgänge eine Aktion erfordern, kann die Aktion den Status nicht direkt ändern. Die Statusdaten müssen weiterhin durch Mutation geändert werden. Basierend auf den Zustandsänderungen wird es schließlich für die Ansicht gerendert.

Vuex löst das Problem, dass mehrere Ansichten auf demselben Status basieren und das Verhalten verschiedener Ansichten denselben Status ändern muss, indem die Energie des Entwicklers auf die Aktualisierung von Daten und nicht auf die Übertragung von Daten zwischen Komponenten konzentriert wird.

Ich werde Ihnen kein Beispiel für die Verwendung von Vuex geben. Ich glaube, jeder ist damit vertraut. Wenn Sie noch Fragen haben, schauen Sie sich die offizielle Dokumentation an: https://vuex.vuejs.org/zh/

 

Fünftens: bereitstellen/injizieren

Konzept: Das Paar Bereitstellungs-/Injektionsoptionen muss zusammen verwendet werden, damit eine Vorgängerkomponente eine Abhängigkeit in alle ihre Nachkommen einfügen kann, unabhängig davon, wie tief die Komponentenhierarchie ist, und sie wird immer wirksam, wenn die Upstream- und Downstream-Beziehungen gleich sind gegründet.

Vereinfacht ausgedrückt werden Variablen über „prove“ in der übergeordneten Komponente bereitgestellt und dann über „inject“ in die untergeordnete Komponente eingefügt.

 

Die Bereitstellungsoption sollte Folgendes sein: ein Objekt oder eine Funktion, die ein Objekt zurückgibt;

Die Injektionsoption sollte sein: ein String-Array oder ein Objekt. Der Schlüssel des Objekts ist der lokale Bindungsname.

 

Schauen wir uns das folgende Beispiel an:

Es gibt jetzt drei Komponenten: Father.vue Sun.vue Grandson.vue wobei Sun.vue eine Unterkomponente von Father.vue und Grandson.vue eine Unterkomponente von Sun.vue ist.

Code der übergeordneten Komponente:

<template>
  <div>
    <p>我是父组件</p>
    <son />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son
  }
})
 
export default class father extends Vue {
  @Provide() text = "I am father"
}
 
</script>

Sohnkomponentencode:

<template>
  <div>
    <p>我是儿子组件</p>
    <grandson />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Inject } from "vue-property-decorator";
import grandson from "./grandson.vue"
 
@Component({
  name: 'son',
  components: {
    grandson
  }
})
 
export default class father extends Vue {
  @Inject() readonly text!: string
 
  mounted () {
    console.log(`儿子组件拿到了:${this.text}`) //儿子组件拿到了:I am father
  }
}
 
</script>

Sun Tzu-Komponentencode:

<template>
  <div>
    <p>我是孙子组件</p>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Inject} from "vue-property-decorator";
 
@Component({
  name: 'grandson',
  components: {
     
  }
})
 
export default class father extends Vue {
  @Inject() readonly text!: string
 
  mounted () {
    console.log(`孙子组件也拿到了:${this.text}`)  //孙子组件也拿到了:I am father
  }
}
 
</script>

Die übergeordnete Komponente stellt das Textattribut bereit, das in den untergeordneten und Enkelkomponenten abgerufen werden kann. Es kann auch direkt auf tieferen Ebenen abgerufen werden, und es ist nicht erforderlich, es Schicht für Schicht zu übergeben.

Die Bereitstellungs-/Injektions-API löst hauptsächlich das Kommunikationsproblem zwischen stufenübergreifenden Komponenten, ihr Verwendungsszenario besteht jedoch hauptsächlich darin, dass Unterkomponenten den Status übergeordneter Komponenten erhalten, und es wird eine Beziehung zwischen aktiver Bereitstellung und Abhängigkeitsinjektion zwischen stufenübergreifenden Komponenten hergestellt .

Tatsächlich können Sie sich die Abhängigkeitsinjektion als Teil „allgemein gültiger Requisiten“ vorstellen, mit Ausnahme von:

  • Eine Vorgängerkomponente muss nicht wissen, welche Nachkommenkomponenten die von ihr bereitgestellten Eigenschaften verwenden
  • Nachkommenkomponenten müssen nicht wissen, woher die injizierten Eigenschaften stammen

Allerdings hat die Abhängigkeitsinjektion immer noch negative Auswirkungen. Es koppelt die Komponenten in Ihrer Anwendung an die Art und Weise, wie sie aktuell organisiert sind, was die Umgestaltung erschwert. Außerdem reagieren die bereitgestellten Eigenschaften nicht. Dies ist beabsichtigt, da es nicht ausreicht, sie zur Erstellung einer zentralisierten Datenskala zu verwenden. Wenn die Eigenschaft, die Sie teilen möchten, anwendungsspezifisch und nicht generisch ist oder Sie die bereitgestellten Daten in einer Vorgängerkomponente aktualisieren möchten, bedeutet dies, dass Sie möglicherweise zu einer echten Lösung wie der Vuex State-Verwaltungslösung wechseln müssen.

 

6. EventBus

EventBus wird auch Event Bus genannt. Es kann als Kommunikationsbrückenkonzept in Vue verwendet werden. Es ist so, als ob alle Komponenten dasselbe Event Center nutzen. Sie können sich registrieren, um Ereignisse zu senden oder Ereignisse an das Center zu empfangen, sodass Komponenten andere Komponenten benachrichtigen können.

Diese Methode verwendet eine leere Vue-Instanz als zentralen Ereignisbus (Ereigniszentrum), löst Ereignisse aus und wartet auf Ereignisse und implementiert die Kommunikation zwischen beliebigen Komponenten, einschließlich Eltern-Kind-Komponenten, Brüdern und Ebenen übergreifend, auf clevere und einfache Weise.

 

Spezifische Implementierungsmethoden:

const EventBus=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});

Schauen wir uns als nächstes Beispiele an:

Jetzt besteht die übergeordnete Komponente aus zwei Komponenten: Children.vue und Children2.vue. Als Nächstes sehen wir uns an, wie diese beiden Komponenten über EventBus kommunizieren.

Zunächst müssen Sie einen Ereignisbus erstellen und exportieren, damit andere Module ihn verwenden oder abhören können.

Initialisierung: event-bus.js

// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

Code der übergeordneten Komponente:

<template>
  <div>
    <p>我是父组件</p>
    <son />
    <son2 />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
import son2 from "./children2.vue"
 
@Component({
  name: 'father',
  components: {
    son,
    son2
  }
})
 
export default class father extends Vue {
  
}
</script>

 

Code der Unterkomponente 1:

// 在儿子1组件中发送事件
<template>
  <div>
    <p>我是儿子1组件</p>
    <el-button @click="addNumber">+加法器</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import {EventBus} from './event-bus.js'
 
@Component({
  name: 'son',
  components: {
  }
})
 
export default class son extends Vue {
  num: number = 1
 
  addNumber() {
    EventBus.$emit('addition', {
      num:this.num++
    })
  }
     
}
</script>

 

Code der Unterkomponente 2:

//儿子2组件中接收事件
<template>
  <div>
    <p>我是儿子2组件</p>
    <div>计算所得结果: {
   
   {count}}</div>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import {EventBus} from './event-bus.js'
 
@Component({
  name: 'son2',
  components: {
    
  }
})
 
export default class son extends Vue {
    count: number = 0;
 
    mounted() {
      EventBus.$on('addition', (param: any) => {
        this.count = this.count + param.num;
      })
    }
     
 
}
 
</script>

Auf diese Weise können Sie in der Komponente „Children.vue“ auf die Schaltfläche „Addierer“ klicken und die übergebene Zahl verwenden, um das Summierungsergebnis in „Children2.vue“ anzuzeigen.

EventBus vereinfacht die Kommunikation zwischen Komponenten, weist jedoch auch Nachteile auf: Wenn das Projekt groß ist, kann es leicht zu schwer zu wartenden Katastrophen kommen.

 

7. $attrs und $listeners

$attrs: Enthält Attributbindungen (außer Klasse und Stil), die im übergeordneten Bereich nicht als Requisiten erkannt (und abgerufen) werden. Wenn eine Komponente keine Requisiten deklariert, werden alle übergeordneten Bereichsbindungen (außer Klasse und Stil) hier einbezogen, und interne Komponenten können über v-bind="$attrs" übergeben werden.

$listeners: Enthält v-on-Ereignis-Listener im übergeordneten Bereich (ohne .native-Modifikator). Es kann über v-on="$listeners" an interne Komponenten übergeben werden.

Lassen Sie uns nun eine Situation besprechen. Nun stehen die Elternkomponente und die Enkelkomponente in einer Generationenbeziehung. Auf welche Weise haben sie zuvor kommuniziert?

  • Verwenden Sie die Props-Bindung, um Informationen Ebene für Ebene zu übertragen. Wenn die Statusänderung in der Enkelkomponente die Übergabe von Daten an die übergeordnete Komponente erfordert, verwenden Sie das Ereignissystem, um sie Ebene für Ebene nach oben zu übergeben.
  • In diesem Fall ist die Verwendung von EventBus immer noch besser geeignet. Wenn jedoch mehrere Personen bei der Entwicklung zusammenarbeiten, ist die Wartbarkeit des Codes und auch die Lesbarkeit gering.
  • Verwenden Sie vuex für die Datenverwaltung. Wenn Sie jedoch nur Daten ohne Zwischenverarbeitung übertragen, fühlt sich die Verwendung von vuex für die Verarbeitung etwas übertrieben an.

Schauen wir uns das folgende Beispiel an:

Code der übergeordneten Komponente:

<template>
  <div>
    <p>我是父组件</p>
    //这里我们可以看到,父组件向儿子组件传递了四个参数和一个方法
    <son
      :name="name"
      :age="age"
      :gender="gender"
      title="我是父组件传过来的title"
      v-on:upText="clickText"
    />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son
  }
})
 
export default class father extends Vue {
  name: string = 'fatherName';
  age: number = 45;
  gender: string = '男'
 
  clickText(val: string) {
    console.log(`当前val是:${val}`); //子组件触发打印:当前val是:I am son    //孙子组件触发打印:当前val是:I am grandson
  }
}
 
</script>

 

Sohnkomponentencode:

<template>
  <div>
    <p>我是儿子组件</p>
    <p>儿子组件的$attrs: {
   
   { $attrs }}</p>
    <el-button @click="tellFather">点击传值给父组件</el-button>
    <grandson v-bind="$attrs" v-on="$listeners" />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import grandson from "./grandson.vue"
 
@Component({
  name: 'son',
  components: {
    grandson
  }
})
 
export default class son extends Vue {
  @Prop({
    default: '男'
  })
  gender!: string; //性别作为props属性绑定
 
  created() {
    // 这里的$attrs就是所有从父组件传递过来的所有参数 然后 除去props中显式定义的参数后剩下的所有参数!!!
 
    console.log(this.$attrs,'attrs'); //age:45   name:fatherName  title:我是父组件传过来的title
 
    console.log(this.$listeners,'listeners') //upText:function
  }
 
  tellFather() {
    this.$emit('upText','I am son')
  }
}
 
</script>

 

Sun Tzu-Komponentencode:

<template>
  <div>
    <p>我是孙子组件</p>
    <p>孙子组件的$attrs: {
   
   { $attrs }}</p>
    <el-button @click="tellGrandFather">点击传值给爷爷组件</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop} from "vue-property-decorator";
 
@Component({
  name: 'grandson',
  components: {
     
  }
})
 
export default class grandson extends Vue {
  @Prop({
    default: '12'
  })
  age!: string; //子组件传过来的age作为props被绑定
 
 
  created() {
    // 同理,$attrs这个对象集合中的值 = 所有传值过来的参数 - props中显示定义的参数
    console.log(this.$attrs,'孙子组件的attrs'); //name: fatherName title:我是父组件传过来的title
 
    console.log(this.$listeners,'孙子组件的listeners'); // upText:function
  }
 
  tellGrandFather() {
    this.$emit('upText','I am grandson'); //触发upText事件,直接进行跨级通信
  }
}
 
</script>

 

Im Allgemeinen gilt: $attrs und $listeners sind zwei Objekte. $attrs speichert Nicht-Props-Attribute, die in der übergeordneten Komponente gebunden sind, und $listeners speichert nicht-native Ereignisse, die in der übergeordneten Komponente gebunden sind. Ein Teil der ebenenübergreifenden Kommunikation kann problemlos über $attrs und $listeners durchgeführt werden.

 

Zusammenfassung am Ende geschrieben:

Entsprechend den gängigen Nutzungsszenarien lassen sie sich grob in drei Kategorien einteilen:

  • Kommunikation zwischen übergeordneten und untergeordneten Komponenten: props; $parent / $children; ref ; Provide / inject ; $attrs / $listeners
  • Kommunikation zwischen Geschwisterkomponenten: eventBus; vuex;
  • Kommunikation auf mehreren Ebenen: vuex; eventBus; bereitstellen / injizieren; $attrs / $listeners

 

Es gibt viele Möglichkeiten, zwischen Komponenten zu kommunizieren. Die Auswahl verschiedener Kommunikationsmethoden in geeigneten Szenarien erhöht auch die Benutzerfreundlichkeit bei der Entwicklung.

おすすめ

転載: blog.csdn.net/weixin_46422035/article/details/114540124