将数据从Component传递到Root

时间:2017-03-21 10:54:18

标签: vue.js vuejs2

假设这个组件:

<template>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">Example Component</div>
                    <div class="panel-body">
                        I'm an example component!
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
          return {
              items: [
                  { message: 'Test 1' },
                  { message: 'Test 2' },
                  { message: 'Test 3' },
              ]
            }
        },
        mounted() {
            console.log('Component mounted.')
        }
    }
</script>

这是我的app.js

Vue.component('example', require('./components/Example.vue'));

const app = new Vue({
    el: '#app'
});

现在,我需要在示例组件中打印所有items,如下所示:

<ul id="example-2">
   <li v-for="(item, index) in items">
       @{{ index }} - @{{ item.message }}
   </li>
</ul>

它返回以下错误:

  

[Vue警告]:未在实例上定义属性或方法“items”   但在渲染期间引用。确保声明反应数据   数据选项中的属性。 (找到)

主要问题是:

如何将子组件中的数据传递给Root?

任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:4)

您可以通过三种方式进行非父子(直接关系)沟通。

  1. 从子组件发出一个事件,然后进一步从接收父级发出值,直到root收到该值。 (不要用这个)

  2. 使用event bus,如果您的应用程序规模较小,这就是您正在寻找的答案。

  3. 使用vuex,如果您的应用程序更多地使用组件状态/是大规模应用程序,这就是您正在寻找的答案。

  4. 示例

    // assuming your component
    import { mapActions } from 'vuex'
    
    export default {
        data() {
          return {
              items: [
                  { message: 'Test 1' },
                  { message: 'Test 2' },
                  { message: 'Test 3' },
              ]
            }
        },
        mounted() {
            console.log('Component mounted.')
            this.setItemsToStore(this.items)
        },
        methods: {
          ...mapActions({
            'setItemsToStore': 'SET_ITEMS_TO_STORE'
          })
        }
    }
    

    然后在main.js中连接vuex

    import Vue from 'vue'
    import { store } from './path/to/store'
    import App from './path/to/App'
    
    new Vue({
      el: '#app',
      store,
      template: '<App/>',
      components: { App }
    })
    

    设置模块化vuex商店,如:

    import Vue from 'vue'
    import Vuex from 'vuex'
    import itemStore from './modules/itemStore'
    
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({
      modules: {
        itemStore
      }
    })
    

    最后你的itemStore看起来像:

    const state = {
      ITEMS: []
    }
    
    const getters = {
      GET_ITEMS: (state) => {
        return state.ITEMS
      }
    }
    
    const mutations = {
      MUTATE_ITEMS: (state, payload) => {
        state.ITEMS = payload
      }
    }
    
    const actions = {
      SET_ITEMS_TO_STORE: ({commit}, payload) => {
        commit('MUTATE_ITEMS', payload)
      }
    }
    
    export default {
      state,
      getters,
      mutations,
      actions
    }
    

    完成此设置后,您的app.js可以像以下一样使用它:

    import { mapGetters } from 'vuex'
    
    const app = new Vue({
      el: '#app',
      computed: {
        ...mapGetters({
          'items': 'GET_ITEMS'
        })
      }
    });
    

    示例2

    //bus.js
    
    export new Vue()
    

    这是一个空的vue实例,将在整个应用程序中使用。

    // your assumed component
    import eventBus from 'path/to/bus.js'
    
    export default {
      data() {
        return {
         items: [
              { message: 'Test 1' },
              { message: 'Test 2' },
              { message: 'Test 3' },
           ]
         }
      },
      mounted() {
        console.log('Component mounted.')
        eventBus.$emit('items-evt', this.items)
      }
    }
    

    在这里,您只需在安装组件时发出事件。

    // app.vue
    import eventBus from 'path/to/bus.js'
    
    const app = new Vue({
      el: '#app',
      data () {
        return {
          items: []
        }
      },
      created () {
        eventBus.$on('items-evt', (items) => {
          this.items = items
        })
      }
    });
    

    在应用程序组件创建时刻录。