Vue组件$ emit触发两次

时间:2018-11-08 11:46:55

标签: javascript jquery vue.js jquery-select2

我最近正在尝试在某些实际应用程序中重用我的Vue组件,以消除不必要的重复内容并用<divs>弄乱。

但是我这样做很麻烦。几个小时后,我设法“完成”它,但是现在事件触发了两次,我不知道为什么。

我已经进行了基本设置以显示问题:

Vue.component("bs-select",{
template:
 `<div class="form-group">
    <label class="control-label">{{ label }}</label>
    <select2
      ref="select2control"
      :options="options"
      :value="value"
      @input="chosenOption"
    ></select2>
  </div>`,
  props: ["value", "label", "options"],
  methods: {
    chosenOption(val) {
      this.$emit("input", val);
    }
  }
});

Vue.component("select2",{
template:
 `<select :value="value" style="width: 100%">
    <option value="" selected disabled>Choose...</option>
    <option v-if="!options">{{ value }}</option>
    <option v-for="option in options" :value="option.value">{{ option.text }}</option>
  </select>`,
  props: ["value", "options"],
  mounted: function() {
    const vm = this;

    $(vm.$el)
      .select2()
      .on("change", function() {
        console.log("CHANGE", vm.$el.value);
        vm.$emit("input", vm.$el.value);
      });
  },
  watch: {
    value: function(val) {
      $(this.$el)
        .val(val)
        .trigger("change");
    }
  }
});

new Vue({
  el: "#app",
  data: {
    test: "bug",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "bug",
      text: "Bug"
    }
    ]
  }
})
* {
  font-family: Arial;
  font-size: 10px;
}

div {
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">
  <bs-select v-model="test" :options="options"></bs-select>
  <br><br>
  <button @click="test = 'bug'">
  Set 'test' variable to 'bug' (Two-way check)
  </button>
{{ test }}
</div>

<div>
Event is firing twice in console...
</div>

我也用Google搜索了很多,但仍未得出关于为什么发生这种情况和/或如何解决此问题的结论。

非常感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

我不确定您在这里到底想做什么,但是我猜您是两次触发onchange事件,一次是在实际更改时,一次是在观察程序中触发。无论如何,当有可用的vue解决方案时,您实际上并不需要像这样使用侦听器:

  grid.draw(12, [&]{a.draw()});

组件:

 <div id="app">
  <bs-select :value="test" v-on:change-value="test = $event" :options="options"></bs-select>
  <br><br>
  {{ test }}

  <br><br>

  <button @click="test = 'bug'">
  Set 'test' variable to 'bug'
  </button>
</div>

<div>
Event is firing twice in console...
</div>

https://jsfiddle.net/kv3bq1dw/

答案 1 :(得分:0)

问了我的一些朋友后,一个人发现“更改”触发器必须位于beforeUpdate中。

因此,已解决的代码如下:

Vue.component("bs-select",{
template:
 `<div class="form-group">
    <label class="control-label">{{ label }}</label>
    <select2
      ref="select2control"
      :options="options"
      :value="value"
      @input="chosenOption"
    ></select2>
  </div>`,
  props: ["value", "label", "options"],
  methods: {
    chosenOption(val) {
      this.$emit("input", val);
    }
  }
});

Vue.component("select2",{
template:
 `<select :value="value" style="width: 100%">
    <option value="" selected disabled>Choose...</option>
    <option v-if="!options">{{ value }}</option>
    <option v-for="option in options" :value="option.value">{{ option.text }}</option>
  </select>`,
  props: ["value", "options"],
  mounted: function() {
    const vm = this;

    $(vm.$el)
      .select2()
      .on("change", function() {
        console.log("CHANGE", vm.$el.value);
        vm.$emit("input", vm.$el.value);
      });
  },
	beforeUpdate() {
  	$(this.$el).val(this.value).trigger('change.select2')
  }
});

new Vue({
  el: "#app",
  data: {
    test: "hello",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "solved",
      text: "Solved"
    }
    ]
  }
})
* {
  font-family: Arial;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script></script>

<div id="app">
  <bs-select v-model="test" :options="options"></bs-select>
  <br><br>
  {{ test }}
  
  <br><br>
  
  <button @click="test = 'solved'">
  Set 'test' variable to 'solved'
  </button>
</div>

效果很好,但他还建议我使用this approach,它更干净。我现在正在使用它,但是如果有人需要,我也会保留该问题的原始答案。

答案 2 :(得分:0)

对于现在遇到这种情况的任何人,这是使它仅发射一次的正确方法。

<template>
    <select><slot></slot></select>
</template>
<script>
  module.exports = {
    props: ['options', 'value'],
    mounted: function () {
        console.log(this.options);
        var vm = this;
        $(this.$el)
        // init select2
        .select2({
            data: this.options,
            theme: 'bootstrap',
            width: '100%',
            placeholder: 'Select',
            allowClear: true
        })
        .val(this.value)
        .trigger('change')
        // emit event on change.
        .on('select2:select', function () { // bind to `select2:select` event
            vm.$emit('input', this.value)
        });
    },
    watch: {
        value: function (value) {
            // update value
            $(this.$el)
            .val(value)
            .trigger('change');
        },
        options: function (options) {
            // update options
            $(this.$el).empty().select2({ data: options })
        }
    },
    destroyed: function () {
        $(this.$el).off().select2('destroy')
    }
  }
</script>