Üst olaylarda alt bileşende işlev çağırma


164

bağlam

Vue 2.0'da belgeler ve diğerleri , ebeveynlerden çocuğa olan iletişimin sahne aracılığıyla gerçekleştiğini açıkça göstermektedir.

Soru

Bir ebeveyn, çocuğuna sahne aracılığıyla bir olayın gerçekleştiğini nasıl söyler?

Olay adında bir pervane izlemeli miyim? Bu doğru hissetmez ve alternatifler de yapmaz ( $emit/ $onçocuk için ebeveyn içindir ve bir hub modeli uzak öğeler içindir).

Misal

Bir üst kapsayıcı var ve onun alt kapsayıcı bir API üzerinde bazı eylemlerde bulunmanın sorun olmadığını söylemek gerekir. Fonksiyonları tetikleyebilmem gerekiyor.

Yanıtlar:


235

Çocuk bileşen a ver refve kullanımı $refsdoğrudan çocuk bileşeni üzerinde bir yöntemi çağırmak için.

html:

<div id="app">
  <child-component ref="childComponent"></child-component>
  <button @click="click">Click</button>  
</div>

javascript:

var ChildComponent = {
  template: '<div>{{value}}</div>',
  data: function () {
    return {
      value: 0
    };
  },
  methods: {
    setValue: function(value) {
        this.value = value;
    }
  }
}

new Vue({
  el: '#app',
  components: {
    'child-component': ChildComponent
  },
  methods: {
    click: function() {
        this.$refs.childComponent.setValue(2.0);
    }
  }
})

Daha fazla bilgi için bkz . Ref ile ilgili Vue belgeleri .


13
Bu şekilde ebeveyn ve alt bileşenler birleşir. Gerçek olaylar için, sadece bir eylemi tetiklemek için bir pervaneyi değiştiremediğinizde, @Roy J
Jared

3
dokümanlar için bir referans da yararlı olacaktır vuejs.org/v2/guide/…
ctf0

Çocuk bileşenimde, özel nedenlerle, reaktiviteyi sonlandırmak için v-once kullanmak zorunda kaldım. Böylece pervanenin ebeveynten çocuğa geçmesi bir seçenek değildi, bu yüzden bu çözüm hile yaptı!
John

1
acemi soru: Neden bir pervane oluşturmakref yerine , değerini izleyen ve daha sonra üstteki başka bir işleve yayan bir pervane mi kullanıyorsunuz? Demek istediğim, yapacak çok şey var, ama refgüvenli kullanıyor mu? Teşekkürler
Irfandy Jip

5
@IrfandyJip - evet, refgüvende. Genellikle, cesaret kırılır, çünkü Vue topluluğu devleti çocuklara ve olayları ebeveyne aktarmayı tercih eder. Genel olarak konuşursak, bu daha izole, dahili olarak tutarlı bileşenlere yol açar (iyi bir şey ™). Ancak, çocuğa ilettiğiniz bilgiler gerçekten bir olay (veya bir komut) ise, durumu değiştirmek doğru kalıp değildir. Bu durumda, a kullanarak bir yöntemi çağırmak reftamamen iyidir ve çökmeyecektir.
joerick

77

Tanımladığınız şey, üst öğedeki durum değişikliğidir. Bunu bir pervane ile çocuğa geçirirsiniz. Önerdiğiniz gibi, watchbu pervane olur. Çocuk harekete geçtiğinde, ebeveyne bir aracılığıyla bildirim gönderir emitve ebeveyn daha sonra durumu tekrar değiştirebilir.

Olayları bir çocuğa gerçekten iletmek istiyorsanız, bunu bir otobüs (yalnızca bir Vue örneği) oluşturarak ve onu bir pervane olarak çocuğa ileterek yapabilirsiniz .


2
Bu resmi Vue.JS stil rehberi ve en iyi uygulamalar doğrultusunda tek cevap olduğunu düşünüyorum. v-modelBileşen üzerinde stenografi kullanırsanız, ilgili olayı daha az kodla yayarak değeri kolayca sıfırlayabilirsiniz.
Falco

Örneğin, bir kullanıcı bir düğmeyi tıkladığında uyarı vermek istiyorum. Örneğin şunu öneriyorsunuz: - bir bayrağı izleyin - bir tıklama gerçekleştiğinde bu bayrağı 0'dan 1'e ayarlayın, - bir şeyler yapın - bayrağı sıfırlayın
Sinan Erdem

9
Çok rahatsız edici, propbir çocukta fazladan, fazladan bir mülk oluşturmak datave sonra eklemek zorundasınız watch... Olayları ebeveynlerden çocuğa bir şekilde aktarmak için yerleşik destek olsaydı rahat olurdu. Bu durum oldukça sık görülür.
Илья Зеленько

1
@ ИльяЗеленько tarafından devlet olarak, oldukça sık gerçekleşir, şu anda bir nimettir.
Craig

1
Teşekkürler @ RoyJ, sanırım çocuk buna abone olduğunda otobüs pervane var olmasını gerektirir, çocuklara olay gönderme tüm fikrinin Vue cesaretini varsayalım.
Ben Winding

35

Sen kullanabilirsiniz $emitve $on. @RoyJ kodunu kullanarak:

html:

<div id="app">
  <my-component></my-component>
  <button @click="click">Click</button>  
</div>

javascript:

var Child = {
  template: '<div>{{value}}</div>',
  data: function () {
    return {
      value: 0
    };
  },
  methods: {
    setValue: function(value) {
        this.value = value;
    }
  },
  created: function() {
    this.$parent.$on('update', this.setValue);
  }
}

new Vue({
  el: '#app',
  components: {
    'my-component': Child
  },
  methods: {
    click: function() {
        this.$emit('update', 7);
    }
  }
})

Çalışan örnek: https://jsfiddle.net/rjurado/m2spy60r/1/


6
Çalıştığına şaşırdım. Bir çocuğa yaymanın bir anti-desen olduğunu ya da niyetin sadece çocuktan ebeveyne olmak olduğunu düşündüm. Diğer tarafa geçme konusunda herhangi bir potansiyel problem var mı?
jbodily

2
Bu en iyi yol olarak düşünülmeyebilir, bilmiyorum, ama ne yaptığını biliyorsan, sorun değil. Diğer yol ise merkezi otobüs kullanmaktır: vuejs.org/v2/guide/…
drinor

14
Bu, çocuk ve ebeveyn arasında bir bağlantı oluşturur ve kötü uygulama olarak kabul edilir
morrislaptop

5
Bu yalnızca üst öğenin bir bileşen değil aslında bir vue uygulaması olması nedeniyle çalışır. Gerçekte bu vue örneğini veri yolu olarak kullanıyor.
Julio Rodrigues

2
@Bsienn bu. $ Parent çağrısı bu bileşeni üst öğeye bağımlı hale getirir. $ emit to and props komutunu kullanır, böylece tek bağımlılıklar Vue'nun iletişim sisteminden geçer. Bu yaklaşım, aynı bileşenin bileşen hiyerarşisinde herhangi bir yerde kullanılmasına izin verir.
morrislaptop

6

Vaktiniz varsa, değişkenleri izlemek için Vuex mağazasını kullanın (durum olarak da bilinir) veya bir eylemi doğrudan tetiklemek (aka olarak göndermek).


2
vuejs / vuex'in en iyi yaklaşım olan reaktivitesi nedeniyle, ebeveynte bir vuex özellik değerini değiştiren bir eylem / mutasyon yapar ve çocukta bu aynı vuex $ store.state.property.value veya "saatini alır" "vuex olduğunda bir şeyler yapan yöntem" $ store.state.property.value "değişiyor
FabianSilva

6

Olay otobüsü$on sırasında çocukta ciltleme kullanarak yaklaşım beğenmedi create. Neden? Sonraki createçağrılar (kullanıyorum vue-router), ileti işleyicisini birden çok kez bağlar ve her ileti için birden çok yanıta neden olur.

Aksesuarı ebeveynlerden çocuğa geçirmenin ve çocuğa bir mülk izleyicisini koymanın ortodoks çözümü biraz daha iyi çalıştı . Tek sorun, çocuğun sadece bir değer geçişi üzerinde hareket edebilmesidir. Aynı mesajı birden çok kez iletmek, geçişi zorlamak için bir tür defter tutma gerektirir, böylece çocuk değişikliği alabilir.

Mesaj bir diziye sarılırsa, değer aynı kalsa bile her zaman çocuk izleyiciyi tetikleyeceğini buldum.

Veli:

{
   data: function() {
      msgChild: null,
   },
   methods: {
      mMessageDoIt: function() {
         this.msgChild = ['doIt'];
      }
   }   
   ...
}

Çocuk:

{
   props: ['msgChild'],
   watch: {
      'msgChild': function(arMsg) {
         console.log(arMsg[0]);
      }
   }
}

HTML:

<parent>
   <child v-bind="{ 'msgChild': msgChild }"></child>
</parent>

1
Ben msgChild üst üzerinde her zaman aynı durumu varsa bu işe yaramaz düşünüyorum. Örneğin: Kalıcı bir bileşen açan bir bileşen istiyorum. Ebeveyn, mevcut durumun açık veya kapalı olup olmadığını umursamıyor, sadece herhangi bir anda modal açmak istiyor. Böylece, üst öğe bunu yaparsa .msgChild = true; mod kapalı ve daha sonra ebeveyn bunu yapıyor.msgChild = true, çocuk olayı almayacak
Jorge Sainz

1
@JorgeSainz: Bu yüzden, veri öğesine atamadan önce değeri bir dizide kaydırıyorum. Değeri bir diziye sarmadan, belirttiğiniz gibi davranır. Yani, msgChild = true, msgChild = true - olay yok. msgChild = [doğru], msgChild = [doğru] - olay!
Jason Stewart

1
Görmedim. Açıklama için teşekkürler
Jorge Sainz

Bu harika, ama biraz huysuz hissettiriyor. Bunu kullanacağım, çünkü bileşen ref hack kullanmaktan daha temiz ve olay veri yolu çözümünden daha az karmaşık. Vue'nun ayrılmasını istediğini ve sadece durum değişikliklerinin bileşeni etkilemesine izin verdiğini biliyorum, ancak gerekirse bir çocuğun yöntemlerini çağırmanın yerleşik bir yolu olmalı. Belki bir pervane üzerindeki durumu değiştirdiğinde, izleyicinin bir sonraki durum değişikliğine hazır olması için otomatik olarak varsayılan bir değere sıfırlayabileceğiniz bir değiştirici olabilir. Her neyse bulmanızı gönderdiğiniz için teşekkürler.
Craig

6

Alt bileşenlerdeki yöntemleri çağırmanın basit bir ayrıştırılmış yolu, çocuktan bir işleyici yaymak ve daha sonra üst öğeden çağırmaktır.

var Child = {
  template: '<div>{{value}}</div>',
  data: function () {
    return {
      value: 0
    };
  },
  methods: {
  	setValue(value) {
    	this.value = value;
    }
  },
  created() {
    this.$emit('handler', this.setValue);
  }
}

new Vue({
  el: '#app',
  components: {
    'my-component': Child
  },
  methods: {
  	setValueHandler(fn) {
    	this.setter = fn
    },
    click() {
    	this.setter(70)
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<div id="app">
  <my-component @handler="setValueHandler"></my-component>
  <button @click="click">Click</button>  
</div>

Ebeveyn, çocuk işleyici işlevlerini ve gerektiğinde çağrıları takip eder.


Bu çözümün nereye gittiğini seviyorum ama ebeveyn "tam olarak bu .setter" nedir?
Craig

İşleyici olayına bağımsız değişken olarak alt bileşen tarafından gönderilen setValue işlevi başvurusudur.
nilobarp

2

Aşağıdaki örnek kendi kendini açıklamaktadır. burada refs ve olaylar, ebeveynden ve alt öğeden işleve çağrı yapmak için kullanılabilir.

// PARENT
<template>
  <parent>
    <child
      @onChange="childCallBack"
      ref="childRef"
      :data="moduleData"
    />
    <button @click="callChild">Call Method in child</button>
  </parent>
</template>

<script>
export default {
  methods: {
    callChild() {
      this.$refs.childRef.childMethod('Hi from parent');
    },
    childCallBack(message) {
      console.log('message from child', message);
    }
  }
};
</script>

// CHILD
<template>
  <child>
    <button @click="callParent">Call Parent</button>
  </child>
</template>

<script>
export default {
  methods: {
    callParent() {
      this.$emit('onChange', 'hi from child');
    },
    childMethod(message) {
      console.log('message from parent', message);
    }
  }
}
</script>

1

Bence, ebeveynin çocuğun yöntemlerini kullanmasının gerekliliği hakkında bir düşünceye sahip olmalıyız. Durum değişikliğini izlemek veya sadece hesaplama işlevini kullanmak için çözüm yeterlidir


2
"Ebeveynler asla çocukları kontrol etmekle ilgilenmemeli" derseniz, bunun gerekli olduğu durumlar vardır. Bir geri sayım sayacı bileşeni düşünün. Ebeveyn baştan başlamak için zamanlayıcıyı sıfırlamak isteyebilir. Sadece sahne kullanımı yeterli değildir, çünkü zaman = 60'dan zaman = 60'a gitmek pervane üzerinde değişiklik yapmaz. Zamanlayıcı, ebeveynin uygun şekilde arayabileceği bir 'sıfırlama' işlevini göstermelidir.
tbm

0

tuşunu kullanarak alt bileşeni yeniden yüklemek için tuşu kullanabilirsiniz

<component :is="child1" :filter="filter" :key="componentKey"></component>

Bileşeni yeni filtreyle yeniden yüklemek istiyorsanız, düğmeyi tıklattığınızda alt bileşene filtre uygulayın

reloadData() {            
   this.filter = ['filter1','filter2']
   this.componentKey += 1;  
},

ve işlevi tetiklemek için filtreyi kullanın

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.