Cara mengakses metode anak dari induknya di vue.js

91

Saya memiliki dua komponen bersarang, apa cara yang tepat untuk mengakses metode anak dari induknya?

this.$children[0].myMethod() tampaknya melakukan trik tetapi itu cukup jelek, bukan, cara apa yang bisa lebih baik:

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

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>
al3x
sumber
Pertama, tanyakan pada diri Anda apakah Anda benar-benar perlu. Jika semua status halaman Anda ada di toko, sebagaimana mestinya, komunikasi orang tua-anak tidak diperlukan.
bbsimonbb
7
Status @bbsimonbb berbeda dari acara. Ini secara khusus tentang memicu kejadian anak dari orang tua. Anda juga dapat melakukan apa pun yang Anda akan menggunakan Vuex dengan meneruskan prop downstream tetapi ini mengharuskan komponen anak mengawasi prop / store untuk perubahan sehingga Anda secara efektif meniru RPC dengan perubahan data yang jelas salah ketika yang Anda inginkan hanyalah memicu tindakan di komponen.
Bojan Markovic

Jawaban:

244

Anda dapat menggunakan ref .

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

Jika Anda tidak menyukai kopling yang ketat, Anda dapat menggunakan Bus Acara seperti yang ditunjukkan oleh @Yosvel Quintero. Di bawah ini adalah contoh lain menggunakan bus acara dengan melewati bus sebagai alat peraga.

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

Kode komponen.

<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
sumber
38
Ini adalah jawaban yang benar, yang benar-benar membaca pertanyaan yang sebenarnya. Jawaban yang dipilih sebenarnya menjawab pertanyaan sebaliknya (bagaimana cara memicu metode pada induk dari komponen anak).
Bojan Markovic
1
Tautan untuk Bus Acara yang ditautkan oleh jawaban ini, dialihkan ke Manajemen Negara , setelah membaca komentar @bbsimonbb , ini agak masuk akal.
Eido95
2
Perlu disebutkan jika Anda menggunakan this.$refs., Anda tidak boleh memuat komponen turunan secara dinamis.
1_bug
Terima kasih Pak! Anda menyelamatkan saya dari banyak masalah. Saya sedang memperbaiki masalah produksi dan sangat mencari jawaban! <3
Osama Ibrahim
this.$ref.reftampaknya mengembalikan array. Jadi bagi saya this.$refs.ref[0].autofocus();bekerja
Jozef Plata
27

Komunikasi orang tua-anak di VueJS

Mengingat instance root Vue dapat diakses oleh semua turunan melalui this.$root, komponen induk dapat mengakses komponen turunan melalui this.$childrenlarik, dan komponen turunan dapat mengakses induknya melalui this.$parent, insting pertama Anda mungkin mengakses komponen ini secara langsung.

Dokumentasi VueJS memperingatkan hal ini secara khusus karena dua alasan yang sangat bagus:

  • Itu erat memasangkan orang tua dengan anak (dan sebaliknya)
  • Anda tidak dapat mengandalkan status induk, karena dapat dimodifikasi oleh komponen turunan.

Solusinya adalah dengan menggunakan antarmuka acara khusus Vue

Antarmuka acara yang diimplementasikan oleh Vue memungkinkan Anda untuk berkomunikasi naik turun pohon komponen. Memanfaatkan antarmuka acara khusus memberi Anda akses ke empat metode:

  1. $on() - memungkinkan Anda untuk mendeklarasikan listener pada instance Vue Anda yang akan digunakan untuk mendengarkan peristiwa
  2. $emit() - memungkinkan Anda untuk memicu peristiwa pada contoh yang sama (sendiri)

Contoh penggunaan $on()dan $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>

Jawaban diambil dari posting asli: Berkomunikasi antar komponen di VueJS

Yosvel Quintero Arguelles
sumber
1
Terima kasih, jadi saya akan mencoba untuk saling menguntungkan kode saya melalui acara!
al3x
5
ketika menyalin / menempelkan sesuatu, senang juga menyebutkan sumbernya.
Mihai Vilcu
17
Ini membantu dalam komunikasi dari anak ke orang tua. Tetapi apakah ada cara serupa untuk melakukannya dari orang tua ke anak? Misalnya sebelum saya mengizinkan pengguna untuk menambahkan anak baru, saya ingin semua yang ada divalidasi - logika validasi ada di anak, jadi saya ingin membahas semuanya dan menjalankan misalnya metode validate ().
Mateusz Bartkowiak
66
Ini menjawab pertanyaan yang berlawanan dengan apa yang sebenarnya ditanyakan. Jawaban Desmond Lua menjawab pertanyaan yang sebenarnya.
Bojan Markovic
4
Bus acara adalah # 1 di daftar antipattern vue Chris Fritz . Apa pun yang dapat dimodelkan dengan peristiwa dan status terdistribusi dapat dimodelkan dengan status global dan pengikatan dua arah, dan secara umum keadaan Anda akan jauh lebih baik.
bbsimonbb
1

Ref dan event bus keduanya memiliki masalah saat render kontrol Anda terpengaruh oleh v-if. Jadi, saya memutuskan untuk menggunakan metode yang lebih sederhana.

Idenya adalah menggunakan array sebagai antrian untuk mengirim metode yang perlu dipanggil ke komponen anak. Setelah komponen dipasang, itu akan memproses antrian ini. Ini melihat antrian untuk menjalankan metode baru.

(Meminjam beberapa kode dari jawaban Desmond Lua)

Kode komponen induk:

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

Ini adalah kode untuk 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>

Dan ada banyak ruang untuk perbaikan seperti pindah processMethodsQueueke mixin ...

mohghaderi.dll
sumber
0

Untuk mengkomunikasikan komponen anak dengan komponen anak lain saya telah membuat metode di induk yang memanggil metode pada anak dengan:

this.$refs.childMethod()

Dan dari anak lain saya telah memanggil metode root:

this.$root.theRootMethod()

Itu berhasil untuk saya.

Jonathan Arias
sumber
Jawaban ini tidak memiliki banyak penjelasan
vsync