So greifen Sie vom übergeordneten Element in vue.js auf eine untergeordnete Methode zu

94

Ich habe zwei verschachtelte Komponenten. Wie kann ich vom übergeordneten Element aus auf die untergeordneten Methoden zugreifen?

this.$children[0].myMethod() scheint den Trick zu tun, aber es ist ziemlich hässlich, nicht wahr, was kann besser sein:

<script>
import child from './my-child'

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>
al3x
quelle
Fragen Sie sich zuerst, ob Sie das wirklich brauchen. Wenn sich Ihr gesamter Seitenstatus in einem Geschäft befindet, wie es sein sollte, ist keine Eltern-Kind-Kommunikation erforderlich.
Bbsimonbb
7
@bbsimonbb Status unterscheidet sich von Ereignissen. Hier geht es speziell darum, untergeordnete Ereignisse vom übergeordneten Ereignis auszulösen. Sie können auch alles tun, wofür Sie Vuex verwenden möchten, indem Sie eine Requisite nachgeschaltet übergeben. Dies erfordert jedoch, dass die untergeordnete Komponente die Requisite / den Speicher auf Änderungen überwacht, damit Sie RPC effektiv mit Datenänderungen emulieren können, was einfach falsch ist, wenn Sie nur möchten eine Aktion in der Komponente auslösen.
Bojan Markovic

Antworten:

248

Sie können ref verwenden .

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {}
  },
  template: `
  <div>
     <ChildForm :item="item" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.$refs.form.submit()
    }
  },
  components: { ChildForm },
})

Wenn Sie keine enge Kopplung mögen, können Sie den Event Bus verwenden, wie von @Yosvel Quintero gezeigt. Im Folgenden finden Sie ein weiteres Beispiel für die Verwendung eines Ereignisbusses, indem Sie den Bus als Requisiten übergeben.

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {},
    bus: new Vue(),
  },
  template: `
  <div>
     <ChildForm :item="item" :bus="bus" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.bus.$emit('submit')
    }
  },
  components: { ChildForm },
})

Code der Komponente.

<template>
 ...
</template>

<script>
export default {
  name: 'NowForm',
  props: ['item', 'bus'],
  methods: {
    submit() {
        ...
    }
  },
  mounted() {
    this.bus.$on('submit', this.submit)
  },  
}
</script>

https://code.luasoftware.com/tutorials/vuejs/parent-call-child-component-method/

Desmond Lua
quelle
39
Dies ist die richtige Antwort, die tatsächlich die eigentliche Frage liest. Die ausgewählte Antwort beantwortet tatsächlich die entgegengesetzte Frage (wie eine Methode für das übergeordnete Element aus der untergeordneten Komponente ausgelöst wird).
Bojan Markovic
1
Der Link für Event Bus , den diese Antwort verknüpft, wird an State Management weitergeleitet . Nachdem Sie den Kommentar @bbsimonbb gelesen haben , ist dies irgendwie sinnvoll.
Eido95
2
Wenn Sie verwenden this.$refs., sollten Sie die untergeordnete Komponente nicht dynamisch laden.
1_bug
Danke mein Herr! Du hast mir viel Ärger erspart. Ich habe ein Produktionsproblem behoben und verzweifelt nach Antworten gesucht! <3
Osama Ibrahim
this.$ref.refscheint ein Array zurückzugeben. Also für mich this.$refs.ref[0].autofocus();gearbeitet
Jozef Plata
27

Eltern-Kind-Kommunikation in VueJS

Wenn eine Nachkommen-Vue-Instanz über alle Nachkommen über zugänglich ist this.$root, eine übergeordnete Komponente über das this.$childrenArray auf untergeordnete Komponenten zugreifen kann und eine untergeordnete Komponente über über das Array auf ihre übergeordneten Komponenten zugreifen kann this.$parent, besteht Ihr erster Instinkt möglicherweise darin, direkt auf diese Komponenten zuzugreifen.

Die VueJS-Dokumentation warnt speziell aus zwei sehr guten Gründen davor:

  • Es koppelt die Eltern eng mit dem Kind (und umgekehrt)
  • Sie können sich nicht auf den Status des Elternteils verlassen, da dieser von einer untergeordneten Komponente geändert werden kann.

Die Lösung besteht darin, die benutzerdefinierte Ereignisschnittstelle von Vue zu verwenden

Über die von Vue implementierte Ereignisschnittstelle können Sie im Komponentenbaum auf und ab kommunizieren. Durch die Nutzung der benutzerdefinierten Ereignisschnittstelle haben Sie Zugriff auf vier Methoden:

  1. $on() - Ermöglicht es Ihnen, einen Listener auf Ihrer Vue-Instanz zu deklarieren, mit dem Ereignisse abgehört werden sollen
  2. $emit() - Ermöglicht das Auslösen von Ereignissen auf derselben Instanz (Selbst)

Beispiel mit $on()und $emit():

const events = new Vue({}),
    parentComponent = new Vue({
      el: '#parent',
      ready() {
        events.$on('eventGreet', () => {
          this.parentMsg = `I heard the greeting event from Child component ${++this.counter} times..`;
        });
      },
      data: {
        parentMsg: 'I am listening for an event..',
        counter: 0
      }
    }),
    childComponent = new Vue({
      el: '#child',
      methods: {
      greet: function () {
        events.$emit('eventGreet');
        this.childMsg = `I am firing greeting event ${++this.counter} times..`;
      }
    },
    data: {
      childMsg: 'I am getting ready to fire an event.',
      counter: 0
    }
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>

<div id="parent">
  <h2>Parent Component</h2>
  <p>{{parentMsg}}</p>
</div>

<div id="child">
  <h2>Child Component</h2>
  <p>{{childMsg}}</p>
  <button v-on:click="greet">Greet</button>
</div>

Antwort aus dem ursprünglichen Beitrag: Kommunikation zwischen Komponenten in VueJS

Yosvel Quintero Arguelles
quelle
1
Vielen Dank, also werde ich versuchen, meinen Code über Ereignisse zu verinnerlichen!
Al3x
5
Beim Kopieren / Einfügen ist es schön, auch die Quelle zu erwähnen.
Mihai Vilcu
17
Dies ist hilfreich bei der Kommunikation vom Kind zum Elternteil. Aber gibt es eine ähnliche Möglichkeit, dies von Eltern zu Kindern zu tun? Bevor ich dem Benutzer erlaube, ein neues untergeordnetes Element hinzuzufügen, möchte ich, dass alle vorhandenen validiert werden. Die Validierungslogik befindet sich im untergeordneten Element. Daher möchte ich alle durchgehen und die Methode validate () ausführen.
Mateusz Bartkowiak
66
Dies beantwortet die entgegengesetzte Frage zu dem, was tatsächlich gestellt wurde. Desmond Luas Antwort beantwortet die eigentliche Frage.
Bojan Markovic
4
Der Eventbus ist die Nummer 1 auf Chris Fritz 'Liste der Vue Antipatterns . Alles, was mit Ereignissen und verteiltem Status modelliert werden kann, kann mit globalem Status und bidirektionaler Bindung modelliert werden, und im Allgemeinen sind Sie viel besser dran.
Bbsimonbb
1

Ref und Event Bus haben beide Probleme, wenn Ihr Steuerelement-Rendering von betroffen ist v-if. Also entschied ich mich für eine einfachere Methode.

Die Idee ist, ein Array als Warteschlange zu verwenden, um Methoden zu senden, die an die untergeordnete Komponente aufgerufen werden müssen. Sobald die Komponente bereitgestellt wurde, verarbeitet sie diese Warteschlange. Es überwacht die Warteschlange, um neue Methoden auszuführen.

(Ausleihen eines Codes aus Desmond Luas Antwort)

Übergeordneter Komponentencode:

import ChildComponent from './components/ChildComponent'

new Vue({
  el: '#app',
  data: {
    item: {},
    childMethodsQueue: [],
  },
  template: `
  <div>
     <ChildComponent :item="item" :methods-queue="childMethodsQueue" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.childMethodsQueue.push({name: ChildComponent.methods.save.name, params: {}})
    }
  },
  components: { ChildComponent },
})

Dies ist Code für ChildComponent

<template>
 ...
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    methodsQueue: { type: Array },
  },
  watch: {
    methodsQueue: function () {
      this.processMethodsQueue()
    },
  },
  mounted() {
    this.processMethodsQueue()
  },
  methods: {
    save() {
        console.log("Child saved...")
    },
    processMethodsQueue() {
      if (!this.methodsQueue) return
      let len = this.methodsQueue.length
      for (let i = 0; i < len; i++) {
        let method = this.methodsQueue.shift()
        this[method.name](method.params)
      }
    },
  },
}
</script>

Und es gibt viel Raum für Verbesserungen wie den Wechsel processMethodsQueuezu einem Mixin ...

Mohghaderi
quelle
0

Um eine untergeordnete Komponente mit einer anderen untergeordneten Komponente zu kommunizieren, habe ich eine übergeordnete Methode erstellt, die eine Methode in einem untergeordneten Element aufruft mit:

this.$refs.childMethod()

Und von dem anderen Kind habe ich die Root-Methode genannt:

this.$root.theRootMethod()

Es hat bei mir funktioniert.

Jonathan Arias
quelle
Diesen Antworten fehlt eine Menge Erklärung
vsync