简体   繁体   中英

How to pass data to nested child components vue js?

I get how to pass data from parent to child with props in a situation like:

<template>
<div>
      <div v-for="stuff in content" v-bind:key="stuff.id">
        <ul>
          <li>
            {{ stuff.items }}
          </li>
        </ul>
      </div>
</div>
</template>

<script>
export default {
  name: stuff,
  props: ['content'],
  data () {
    return {

    }
  }
}
</script>

And then bind the data to the component in the parent component like,

<template>
  <div>
    <stuff v-bind:content="stuffToPass"></stuff>
  </div>
</template>
<script>
import stuff from './stuff.vue';
export default {
  data () {
    return {
      stuffToPass: [
        {id: 1, items: 'foo'},
        {id: 2, items: 'bar'},
        {id: 3, items: 'baz'}
      ]
    }
  },
  components: {
    stuff
  }
}
</script>

But say I have the root component, and I want to pass data to the stuff component, like in the above, but when I have a number of other components like parent > x > y > stuff , and it's still the stuff component that will ultimately be receiving that data, I don't know how to do that.

I heard of provide/inject, but I'm not sure that's the appropriate use, or at least I couldn't get it working.

Then I tried passing props, but then I found myself trying to bind a prop to a component to pass as a prop to a child component and that doesn't sound right, so then I just re-wrote my components in the 'stuff' component, but I feel that's probably re-writing way to much code to be close to reasonable.

there are a few possibilities to pass data parent > x > y > stuff

  • props - applicable but you would have to pipe the data through all components...
  • store (vuex) - applicable but could become complicated to handle
  • event bus - the most flexible and direct way

below, a simple example on how to implement the event bus:

// src/services/eventBus.js

import Vue from 'vue';
export default new Vue();

the code from where you want to emit the event:

// src/components/parent.vue

<script>
import EventBus from '@/services/eventBus';

export default {
  ...
  methods: {
    eventHandler(val) {
      EventBus.$emit('EVENT_NAME', val);
    },
  },
  ...
};
</script>

the code for where you want to listen for the event:

// src/components/stuff.vue

<script>
import EventBus from '@/services/eventBus';

export default {
  ...
  mounted() {
    EventBus.$on('EVENT_NAME', val => {
      // do whatever you like with "val"
    });
  },
  ...
};
</script>

Use watchers or computed properties https://v2.vuejs.org/v2/guide/computed.html

 const Stuff = Vue.component('stuff', { props: ['content'], template: `<div> <div v-for="stuff in content" v-bind:key="stuff.id"> <ul> <li> {{ stuff.items }} </li> </ul> </div> </div>` }); const Adapter = Vue.component('adapter', { components: { Stuff }, props: ['data'], template: `<div> <Stuff :content="newData"/> </div>`, data() { return { newData: [] }; }, created() { this.changeData(); }, watch: { data: { deep: true, handler: function() { this.changeData(); } } }, methods: { changeData() { this.newData = JSON.parse(JSON.stringify(this.data)); } } }); const app = new Vue({ el: '#app', components: { Adapter }, data() { return { stuffToPass: [ { id: 1, items: 'foo' }, { id: 2, items: 'bar' }, { id: 3, items: 'baz' } ] }; }, methods: { addItem() { this.stuffToPass.push({ id: this.stuffToPass.length + 1, items: 'new' }); } } });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.1/vue.js"></script> <div id="app"> <button @click="addItem">Add</button> <Adapter :data="stuffToPass"/> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM