【问题标题】:Communication between Vue root and any child componentVue root 和任何子组件之间的通信
【发布时间】:2018-09-06 08:02:32
【问题描述】:

我有一系列深入几个层次的组件。每个组件都有自己的一段数据,它通过 AJAX 加载并用于呈现子组件的每个实例。以days 父模板为例:

<template>
    <accordion :one-at-atime="true" type="info">
        <panel :is-open="index === 0" type="primary" :header="'Day ' + day.day" v-for="(day, index) in days" :key="day.id">
            <br/>
            <div class="panel panel-success">
                <div class="panel-heading">
                    <h3 class="panel-title">Cycles</h3>
                </div>
                <div class="panel-body">
                        <cycles
                            :day="day"
                        >
                        </cycles>
                </div>
            </div>
        </panel>
    </accordion>
</template>

cycles 子模板为例:

<template>
    <accordion :one-at-atime="true" type="info">
        <panel :is-open="index === 0" type="primary" :header="'Week ' + cycle.week + ': ' + cycle.name" v-for="(cycle, index) in cycles" :key="cycle.id">
            <form v-on:submit.prevent="update">
                ....misc input fields here...
<button type="button" class="btn btn-warning" v-if="cycle.id" v-on:click="destroy">Delete</button>
            </form>
        </panel>
    </accordion>
</template>

<script>
    export default {
        props: [
            'day'
        ],
        data() {
            return {
                cycles: []
            }
        },
        beforeMount: function () {
            var self = this;

            if (this.cycles.length === 0) {
                axios.get('/plans/days/' + this.day.id + '/cycles')
                    .then(function (response) {
                        self.cycles = response.data;
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            }
        },
        methods: {
            destroy: function (event) {
                var self = this;

                axios.delete('/plans/cycles/' + event.target.elements.id.value)
                    .then(function (response) {
                        self.cycles.filter(function (model) {
                            return model.id !== response.data.model.id;
                        });
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            }
        }
    }
</script>

每个cycles 组件然后在v-for 循环中呈现另一个组件,该循环呈现另一种类型的组件,依此类推。创建的是一个树状的组件结构。

当我需要向服务器发送一个通用请求,然后更新调用它的组件中的数据时,我不想在每个组件中都复制该请求方法。我宁愿在根 Vue 实例上只拥有该方法的一个实例。

例如,这是首选:

const app = new Vue({
    el: '#app',
    store,
    created: function () {
        this.$on('destroy', function (event, type, model, model_id, parent_id) {
            this.destroy(event, type, model, model_id, parent_id);
        })
    },
    methods: {
        destroy: function (event, type, model, model_id, parent_id) {
            var self = this;

            axios.delete('/plans/' + type + '/' + model_id)
                .then(function (response) {
                    model = model.filter(function (model) {
                        return model.id !== response.data.model.id;
                    });

                    this.$emit('modified-' + type + '-' + parent_id, model);
                })
                .catch(function (error) {
                    console.log(error);
                });
        }
    }
});

然后在cycles.vue 删除按钮中单击时调用:

<button type="button" class="btn btn-warning" v-if="cycle.id" v-on:click="$root.$emit('destroy', event, 'cycles', cycles, cycle.id, day.id)">Delete</button>

并将其添加到 cycles.vue 事件中:

    created: function () {
        this.$on('modified-cycles-' + this.day.id, function (cycles) {
            this.cycles = cycles;
        })
    },

但是,这不起作用,因为子元素永远不会从根获取发出的 'modified-' + type + '-' + parent_id 事件。

我也试过this.$children.$emit('modified-' + type + '-' + parent_id, model);,但也没有用。

Vue 2.5.16 的方法是什么?还有比我目前使用的更好的设计模式吗?

【问题讨论】:

  • 你看过 Vuex 吗? vuex.vuejs.org
  • 我在这个项目中使用了 Vuex,但我不知道如何让它在这个用例中工作。
  • 是否要将this 包含在emit 的有效负载中?
  • @RoyJ 这样做有什么好处?
  • 这将使发出事件的组件可以通过根实例更新其数据。

标签: javascript vue.js vuejs2


【解决方案1】:

每个 Vue 实例(根和子)都是一个独立的事件中心。

您在一个实例上 $emit 事件,并且您可以使用 $on 在同一实例上订阅事件通知。

您可以使用this.$root.$on()this.$root.$emit() 将根实例用作事件总线并达到您的目的。

但是,我不太清楚您要获得什么关注点分离,所以我还没有准备好提供更好的建议。

【讨论】:

  • 我想让我的代码保持干燥。通过将这些常用方法放在根目录中,我只需要其中一个,所有子组件都可以重用它们。
  • 作为一般规则,每个组件都应该负责维护(即分配给)它包含的状态部分(它自己的数据成员)。在您的示例中,该操作似乎是在 Cycles.vue 中启动并最终在同一组件内更改 this.cycles :您为什么要涉及任何其他组件?您可以做的一件事是将 API 调用抽象到一个单独的模块中,您可以从所有组件中导入和使用该模块。
猜你喜欢
  • 2021-02-07
  • 2017-03-25
  • 2018-09-10
  • 2015-11-21
  • 2018-01-10
  • 1970-01-01
  • 2017-03-09
  • 2019-03-19
  • 2017-12-25
相关资源
最近更新 更多