Come accedere a un metodo figlio dal genitore in vue.js


97

Ho due componenti nidificati, qual è il modo corretto per accedere ai metodi figlio dal genitore?

this.$children[0].myMethod() sembra fare il trucco ma è piuttosto brutto, non è vero, quale può essere il modo migliore:

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

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>

Per prima cosa, chiediti se ne hai davvero bisogno. Se tutto lo stato della pagina è in un negozio, come dovrebbe essere, non è necessaria la comunicazione genitore-figlio.
bbsimonbb

7
@bbsimonbb State è diverso dagli eventi. Ciò riguarda specificamente l'attivazione di eventi figlio dal genitore. Puoi anche fare tutto ciò per cui useresti Vuex passando un prop a valle, ma ciò richiede che il componente figlio guardi il prop / store per le modifiche in modo da emulare efficacemente RPC con le modifiche ai dati che è semplicemente sbagliato quando tutto ciò che vuoi è farlo attivare un'azione nel componente.
Bojan Markovic

Risposte:


253

Puoi usare il rif .

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 },
})

Se non ti piace l'accoppiamento stretto, puoi usare Event Bus come mostrato da @Yosvel Quintero. Di seguito è riportato un altro esempio di utilizzo del bus degli eventi passando nel bus come oggetti di scena.

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 },
})

Codice dei componenti.

<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/


39
Questa è la risposta corretta, che effettivamente legge la domanda vera e propria. La risposta selezionata risponde effettivamente alla domanda opposta (come attivare un metodo sul genitore dal componente figlio).
Bojan Markovic

1
Il link per Event Bus che questa risposta sta collegando, sta reindirizzando alla gestione dello stato , dopo aver letto il commento @bbsimonbb , ha senso.
Eido95

2
Vale la pena menzionare se usi this.$refs., non dovresti caricare il componente figlio in modo dinamico.
1_bug

grazie Signore! Mi hai risparmiato un sacco di guai. Stavo risolvendo un problema di produzione e cercavo disperatamente risposte! <3
Osama Ibrahim

this.$ref.refsembra restituire un array. Quindi per me ha this.$refs.ref[0].autofocus();funzionato
Jozef Plata

26

Comunicazione genitore-figlio in VueJS

Dato che un'istanza radice di Vue è accessibile da tutti i discendenti tramite this.$root, un componente padre può accedere ai componenti figlio tramite l' this.$childrenarray e un componente figlio può accedere al suo genitore tramite this.$parent, il tuo primo istinto potrebbe essere quello di accedere direttamente a questi componenti.

La documentazione di VueJS mette in guardia contro questo specificamente per due ottimi motivi:

  • Accoppia strettamente il genitore al bambino (e viceversa)
  • Non puoi fare affidamento sullo stato del genitore, dato che può essere modificato da un componente figlio.

La soluzione è utilizzare l'interfaccia eventi personalizzata di Vue

L'interfaccia degli eventi implementata da Vue consente di comunicare su e giù per l'albero dei componenti. Sfruttando l'interfaccia personalizzata degli eventi puoi accedere a quattro metodi:

  1. $on() - ti consente di dichiarare un listener sulla tua istanza Vue con cui ascoltare gli eventi
  2. $emit() - consente di attivare eventi sulla stessa istanza (self)

Esempio utilizzando $on()e $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>

Risposta presa dal post originale: Comunicazione tra i componenti in VueJS


1
Grazie, quindi proverò a mutualizzare il mio codice tramite eventi!
al3x

5
quando si copia / incolla qualcosa è bello menzionare anche la fonte.
Mihai Vilcu

17
Questo è utile nella comunicazione da bambino a genitore. Ma esiste un modo simile per farlo da genitore a figlio? Ad esempio, prima di consentire all'utente di aggiungere un nuovo figlio, voglio che tutti quelli esistenti vengano convalidati - la logica di convalida è in figlio, quindi voglio esaminarli tutti ed eseguire ad esempio il metodo validate ().
Mateusz Bartkowiak

68
Questo risponde alla domanda opposta a ciò che è stato effettivamente chiesto. La risposta di Desmond Lua risponde alla domanda reale.
Bojan Markovic

4
Event bus è al primo posto nella lista degli antipattern di Chris Fritz . Tutto ciò che può essere modellato con eventi e stato distribuito può essere modellato con stato globale e associazione a due vie, e in generale starai molto meglio.
bbsimonbb

1

Ref e event bus hanno entrambi problemi quando il rendering del controllo è influenzato da v-if. Quindi, ho deciso di utilizzare un metodo più semplice.

L'idea è usare un array come coda per inviare metodi che devono essere chiamati al componente figlio. Una volta che il componente è stato montato, elaborerà questa coda. Controlla la coda per eseguire nuovi metodi.

(Prendendo in prestito un codice dalla risposta di Desmond Lua)

Codice componente genitore:

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 },
})

Questo è il codice per 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>

E c'è molto spazio per migliorare come passare processMethodsQueuea un mixin ...


0

Per comunicare un componente figlio con un altro componente figlio ho creato un metodo in parent che chiama un metodo in un bambino con:

this.$refs.childMethod()

E da un altro bambino ho chiamato il metodo di root:

this.$root.theRootMethod()

Ha funzionato per me.


Questa risposta manca di molte spiegazioni
vsync
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.