【问题标题】:How to update one component from another component in vue.js如何从 vue.js 中的另一个组件更新一个组件
【发布时间】:2017-06-12 19:26:14
【问题描述】:

我有一个基于 vue.js 2.0 界面的网络应用程序。

我有一个基于 select2 插件显示输入的组件。

默认情况下它会显示选定的选项,但是当用户单击它时,我会显示 select2 以允许用户修改选项。

代码如下:

<template>
<div @click="toggleEdit">
    <span v-show="isEnabled">
        <select
            class="form-control"
            :name="name"
            :multiple="multiple"
        >
            <option v-for="opt in options" :value="opt.id"> {{ opt.text }} </option>
        </select>
    </span>
    <span v-show="!isEnabled">
        <div v-if="selectedOptions.length === 0">
            {{ emptyText }}
        </div>
        <div v-for="opt in selectedOptions">
            {{ opt }}
        </div>
    </span>
</div>
</template>
<script>
export default {
    props: {
        options: {
            type: Array,
            required: false,
            default: function() {
                return []
            }
        },
        name: {
            required: true,
            type: String
        },
        multiple: {
            required: false,
            type: Boolean,
            default: false
        },
        emptyText: {
            required: false,
            type: String,
            default: ""
        },
        sourceUrl: {
            required: false,
            type: String,
            default: ""
        },
        enabled: {
            required: false,
            type: Boolean,
            default: false
        }
    },

    data() {
        return {
            isEnabled: this.enabled
        }
    },

    watch: {
        options: {
            handler: function() {
                console.log(arguments)
            },
            deep: true
        }
    },

    mounted: function() {
        this.select = $(this.$el).find("select");
        this.select.select2();
        var that = this;
        this.select.on("change", function(e) {
            var indexMap = {};
            for(var i = 0; i < that.options.length; i++) {
                that.options[i].selected = false;
                indexMap[that.options[i].id] = i;
            }
            var selected = that.select.select2('val');
            if(typeof selected === "string") {
                selected = [selected];
            }
            for(var i = 0; i < selected.length; i++) {
                var index = indexMap[selected[i]];
                console.log(index)
                console.log(selected[i])
                if(index !== undefined) {
                    var option = that.options[index];
                    option.selected = true;
                    that.$set(that.options, index, option);
                }
            }
        })
        this.select.on("select2:open", function() {
            that.isEnabled = true;
        });
        this.select.on("select2:close", function() {
            that.isEnabled = false;
        });
    },
    methods: {
        toggleEdit() {
            if(this.isEnabled) return; // to pass select2 clicks
            this.isEnabled = !this.isEnabled;
            var that = this;
            this.$nextTick(function() {
                that.select.select2("open");
            });
        }
    },
    computed: {
        selectedOptions: function() {
            console.log(this.options)
            return this.options.filter(function(option) {
                console.log(option.selected);
                if(option.selected === true) return true;
                return false;
            });
        }
    }
}

问题是:我想使用这个组件显示多个不同的selects。名称属性可以是以下之一:model1[field1]model1[field2]、...、model40[field1]、...、model99[field15],其中每个 modelN 对应于数据库中的表及其各自的字段。

当用户更改选项时,必须向服务器发送ajax请求,服务器返回json-object是这样的

{
   "errorText": null or "text with error",
   "disableFields": ["model3[field4]", "model24[field15]"]
}

我想解析“disableFields”数组并从this 组件another 组件中禁用。

实现此目的的一种方法(伪代码):

foreach field in disableField:
    $(document).trigger("disableField" + field);

而在this组件的mounted方法中

var self = this;
$(document).on("disableField" + this.name, function() {
    self.isEnabled = false
})

在没有父组件的情况下有没有更好的方法来做到这一点?

【问题讨论】:

  • 未来,尽量缩短。你的问题质量很好,但太长了......

标签: vue.js


【解决方案1】:

你可以在没有全局变量的情况下使用this.$root

// component A emits an event
export default {
  name: 'A',
  methods: {
    buttonClicked: function () {
      this.$root.$emit('myEvent', 'new message!');
    }
  }

// component B catch your event
export default {
  name: 'B',
  data () {
    return {
        message: 'Old message!'
    }
  },
  mounted: function () { 
    this.$root.$on('myEvent', (text) => { // here you need to use the arrow function
     this.message = text;
    })
  }
}

【讨论】:

  • 这条评论帮助我解决了使用 $on 的情况。我想淡化所有其他 v-for 项目,除了我刚刚单击/发出事件的项目,感谢它。
  • 使用 Vuex 状态存储会更好地解决这个问题吗?
【解决方案2】:

不允许直接与其他组件通信。您可以使用父组件在组件之间进行通信或some kind of event bus

var bus = new Vue();

组件 A 发出一个事件,而组件 B 可能会捕获它,反之亦然。

// component A
bus.$emit('cool_event_name', interesting_data)

// component B
bus.$on('cool_event_name', function(interesting_data) {
   console.log(interesting_data)
})

另一种解决方案可能是使用 $root,它可以从 Vue 实例的所有子组件访问。这节省了全球总线的定义(如上)。请注意,这种方法是not recommended 作为一种通用方法,更多的是作为某些边缘情况的解决方案。

// component A
this.$root.$emit('cool_event_name', interesting_data)

// component B
this.$root.$on('cool_event_name', function(interesting_data) {
   console.log(interesting_data)
})

【讨论】:

    【解决方案3】:

    由于您的帖子太长而且内容太多,要真正实现您想要实现的目标并不容易,但我会尝试。如果缺少某些内容,请发表评论,我会尝试编辑以更好地帮助您。

    禁用字段

    我建议将这个数组放在你的父组件的data 中(例如具有整个表单/页面的组件),然后将它传递给你的字段,如&lt;component-instance :disabled='disabled.componentId'&gt; 请注意:disabled。它是数据绑定,它将与您的父数据保持单向同步(这意味着您的父 disabled.componentId 中的每个更改都将反映在您的子组件中)

    解析“禁用”JSON

    我认为这很简单,因为您只需将返回的字段分配给您的 data: { disabled },但如果您无法弄清楚,请告诉我们。

    ** 组件之间的其他通信方式**

    如果你想从 CHILD 组件更新 PARENT,你必须通过 Vue 事件总线或事件的处理程序来使用 EVENTS。 如果不需要从子组件传递特殊数据或在子组件中创建自定义事件发射器,则可以在子组件上使用&lt;child-component @click='yourParentMethod()'&gt;,例如:

    // child component
    methods: {
    someMethod() => {
    this.emit('customEvent', someData)
    }
    }
    
    //parent component
    <child-component @customEvent='customEventHandler(dataFromChild)'> 
    

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2016-07-14
      • 2021-07-23
      • 2020-07-01
      • 2021-06-15
      • 1970-01-01
      • 1970-01-01
      • 2020-10-25
      • 2019-03-08
      • 2018-03-01
      相关资源
      最近更新 更多