web-dev-qa-db-fra.com

Vue - accès aux enfants imbriqués en utilisant ref

J'ai un composant vue que j'utilise à l'intérieur de lui-même - les données peuvent avoir un tableau avec des sous-éléments et j'utilise ce tableau pour les rendre en boucle, et le niveau suivant, le niveau suivant, etc. selon le niveau d'imbrication.

Maintenant, je voudrais exécuter la méthode enfant à partir du parent, puis - si les instructions sont correctes, appelez-la également à l'enfant, au niveau suivant, etc.

J'utilise

    <mycomponent
            ref="myFirstLevelRefName"
            (...)
    ></mycomponent>

et alors:

this.$refs.myFirstLevelRefName 

d'appeler des enfants de premier niveau. Mais qu'en est-il des nœuds enfants? Je les utilise en vue de cette manière:

    <mycomponent
            v-for="(subElement, index) in getSubelements()"
            ref="???"
            v-bind:data="subElement"
            v-bind:key="index"
    ></mycomponent>

J'ai essayé d'envoyer ceci. $ Refs du niveau enfant à la console, mais il est vide.

Comment dois-je définir le nom de référence dans les éléments imbriqués, puis les appeler à partir du parent?

8
Lukasz Tkacz

Bien qu'il soit techniquement possible d'accéder à $refs des enfants imbriqués ...

Vue.component('mycomponent', {
    template: "#mycomponent",
});

new Vue({
  el: '#app',
  mounted() {
    console.log(
      'Second level <input>\'s value:',
      this.$refs.myFirstLevelRefName.$refs.mySecondLevelRefName.value
    )
  }
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>

<template id="mycomponent">
    <div>
        <input ref="mySecondLevelRefName" value="Hello">
    </div>
</template>

<div id="app">
  <mycomponent ref="myFirstLevelRefName"></mycomponent>
</div>

Un moyen d'effectuer une communication parent/enfant profond, ou une communication profonde ancêtre/frère, pour des scénarios simples, consiste à utiliser un hub d'événements . (Pour les scénarios complexes, voir Vuex .)

Vous créeriez une variable globale:

var eventHub = new Vue(); // use a Vue instance as event hub

Pour émettre des événements que vous utiliseriez dans n'importe quel composant:

eventHub.$emit('myevent', 'some value');

Vous auriez alors, dans tout autre composant, à écouter cet événement. L'action de cet événement peut être n'importe quoi, y compris un appel de méthode (ce que vous voulez):

eventHub.$on('myevent', (e) => {
    console.log('myevent received', e)
    // this.callSomeMethod();
});

Démo:

var eventHub = new Vue(); // use a Vue instance as event hub

Vue.component('component-first', {
    template: "#component-1st",
    methods: {
      myMethod() {
        eventHub.$emit('myevent', 'some value');
      }
    }
});
Vue.component('component-second', {template: "#component-2nd"});
Vue.component('component-third', {
  template: "#component-3rd",
  created() {
    eventHub.$on('myevent', (e) => {
      this.check();
    });
  },
  methods: {
    check() {
      console.log('check method called at 3rd level child');
    }
  }
})

new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>

<template id="component-1st">
    <div>
        1st level component
        <button @click="myMethod">Trigger event at 1st level component that will call 3rd level child's method</button>
        <hr>
        <component-second></component-second>
    </div>
</template>
<template id="component-2nd">
    <div>
        <component-third></component-third>
    </div>
</template>
<template id="component-3rd">
    <div><h1>3rd level child</h1></div>
</template>

<div id="app">
  <component-first></component-first>
</div>

Remarque: Si la création d'une instance dédiée en tant que hub d'événements est quelque chose de compliqué dans votre environnement, vous pouvez remplacer eventHub par this.$root (à l'intérieur de vos composants) et utilisez votre propre instance Vue comme hub.

17
acdcjunior