Vue.js'deki üst öğeden bir alt yönteme nasıl erişilir


91

İç içe geçmiş iki bileşenim var, alt yöntemlere üst öğeden erişmenin uygun yolu nedir?

this.$children[0].myMethod() hile yapıyor gibi görünüyor ama oldukça çirkin, değil mi, daha iyi bir yol olabilir:

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

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

İlk önce, kendinize gerçekten ihtiyacınız olup olmadığını sorun. Tüm sayfa durumunuz olması gerektiği gibi bir mağazadaysa, ebeveyn-çocuk iletişimine gerek yoktur.
bbsimonbb

7
@bbsimonbb Durumu olaylardan farklıdır. Bu, özellikle ebeveynden çocuk olaylarının tetiklenmesi ile ilgilidir. Vuex'i kullanmak istediğiniz her şeyi, aşağı akışlı bir pervane aktararak da yapabilirsiniz, ancak bu, alt bileşenin değişiklikler için pervane / depoyu izlemesini gerektirir, böylece RPC'yi veri değişiklikleriyle etkin bir şekilde taklit edebilirsiniz, bu tamamen yanlıştır. bileşende bir eylemi tetikler.
Bojan Markovic

Yanıtlar:


244

Ref kullanabilirsiniz .

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

Sıkı bağlamadan hoşlanmıyorsanız, @Yosvel Quintero tarafından gösterildiği gibi Olay Veriyolunu kullanabilirsiniz . Aşağıda, veri yolunu sahne olarak geçirerek olay veri yolunu kullanmanın başka bir örneği verilmiştir.

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

Bileşenin kodu.

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


38
Asıl soruyu okuyan doğru cevap budur. Seçilen yanıt aslında zıt soruyu yanıtlar (alt bileşenden üst öğede bir yöntem nasıl tetiklenir).
Bojan Markovic

1
İçin bağlantı Olay Bus Bu cevap bağlantı verdiğini, adına yönlendirme Devlet Yönetimi @bbsimonbb okuduktan sonra yorumunu onun tür mantıklı.
Eido95

2
Kullanıyorsanız this.$refs., alt bileşeni dinamik olarak yüklememelisiniz.
1_bug

teşekkürler bayım! Beni çok fazla zahmetten kurtardın. Bir üretim sorununu çözüyordum ve çaresizce yanıtlar arıyordum! <3
Usame İbrahim

this.$ref.refbir dizi döndürüyor gibi görünüyor. Yani benim için this.$refs.ref[0].autofocus();çalıştı
Jozef Plata

27

VueJS'de ebeveyn-çocuk iletişimi

Bir kök Vue örneğine tüm nesiller tarafından erişilebildiği için this.$root, bir ana bileşen alt bileşenlere this.$childrendizi aracılığıyla erişebilir ve bir alt bileşen üst bileşenlerine erişebilir this.$parent, ilk içgüdünüz bu bileşenlere doğrudan erişmek olabilir.

VueJS belgeleri, özellikle iki çok iyi nedenden dolayı buna karşı uyarmaktadır:

  • Ebeveyni çocuğa sıkıca bağlar (ve bunun tersi de geçerlidir)
  • Bir alt bileşen tarafından değiştirilebileceği için ebeveynin durumuna güvenemezsiniz.

Çözüm, Vue'nun özel etkinlik arayüzünü kullanmaktır

Vue tarafından uygulanan olay arayüzü, bileşen ağacında yukarı ve aşağı iletişim kurmanıza olanak tanır. Özel etkinlik arayüzünden yararlanmak size dört yönteme erişmenizi sağlar:

  1. $on() - olayları dinlemek için Vue örneğinizde bir dinleyici bildirmenize olanak tanır
  2. $emit() - aynı örnekte (kendi başına) olayları tetiklemenize izin verir

Örnek kullanılarak $on()ve $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>

Orijinal gönderiden alınan cevap: VueJS'deki bileşenler arasında iletişim


1
Teşekkürler, bu yüzden kodumu etkinlikler yoluyla karşılıklı hale getirmeyi deneyeceğim!
al3x

5
Bir şeyleri kopyalarken / yapıştırırken kaynaktan da bahsetmek güzel.
Mihai Vilcu

17
Bu, çocuktan ebeveyne iletişimde yardımcı olur. Ama bunu ebeveynden çocuğa yapmanın benzer bir yolu var mı? Örneğin, kullanıcının yeni alt öğe eklemesine izin vermeden önce, tüm mevcut olanların doğrulanmasını istiyorum - doğrulama mantığı alt öğede, bu yüzden hepsinin üzerinden geçmek ve örneğin validate () yöntemini çalıştırmak istiyorum.
Mateusz Bartkowiak

66
Bu, gerçekte ne sorulduğunun tersi soruyu yanıtlar. Desmond Lua'nın cevabı asıl soruyu yanıtlıyor.
Bojan Markovic

4
Etkinlik otobüsü, Chris Fritz'in vue antipattern listesinde 1 numara . Olaylar ve dağıtılmış durum ile modellenebilen her şey, küresel durum ve iki yönlü bağlama ile modellenebilir ve genel olarak çok daha iyi durumda olacaksınız.
bbsimonbb

1

Ref ve olay veri yolunun her ikisinde de, denetim işlemeniz etkilendiğinde sorunlar vardır v-if. Bu yüzden daha basit bir yöntem kullanmaya karar verdim.

Buradaki fikir, alt bileşene çağrılması gereken yöntemleri göndermek için bir diziyi kuyruk olarak kullanmaktır. Bileşen monte edildikten sonra bu kuyruğu işleyecektir. Yeni yöntemleri çalıştırmak için kuyruğu izler.

(Desmond Lua'nın cevabından bir kod ödünç almak)

Ana bileşen kodu:

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

Bu, ChildComponent kodudur

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

Ve processMethodsQueuebir miksere geçmek gibi iyileştirme için çok yer var ...


0

Bir alt bileşeni başka bir alt bileşenle iletişim kurmak için, ebeveynde bir çocukta bir yöntemi çağıran bir yöntem yaptım:

this.$refs.childMethod()

Ve başka bir çocuktan kök yöntemi olarak adlandırdım:

this.$root.theRootMethod()

Benim için çalıştı.


Bu
yanıtta
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.