Vue компонент $ Emit стрельбы в два раза - PullRequest
0 голосов
/ 08 ноября 2018

Я недавно пытаюсь повторно использовать компоненты 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>

Я также много гуглил и не пришел к выводу, почему это происходит и / или как решить эту проблему.

Любая помощь с благодарностью.

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Спросив некоторых из моих друзей, один понял, что триггер «изменения» должен быть в 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>

Это работает довольно хорошо, но он также предложил мне использовать этот подход , который намного чище. Сейчас я использую это сейчас, но я оставляю оригинальный ответ и на вопрос, на случай, если кому-то это понадобится.

0 голосов
/ 11 апреля 2019

Для тех, кто сталкивается с этим сейчас, это правильный способ запустить его только один раз.

<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>
0 голосов
/ 08 ноября 2018

Я не уверен, что именно вы пытаетесь сделать здесь, но я предполагаю, что вы запускали событие onchange дважды, один раз, когда он действительно изменился, и один раз в наблюдателе. В любом случае, вам не нужно использовать таких слушателей, когда есть доступные vue-решения:

 <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>

компонент:

Vue.component("bs-select",{
template:
 `<select :value="value" v-on:change="changeVal" 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"],
  methods: {
    changeVal: function(event) {
        this.$emit('change-value', event.target.value)
    }
  }
});

new Vue({
  el: "#app",
  data: {
    test: "bug",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "bug",
      text: "Bug"
    }
    ]
  }
})

https://jsfiddle.net/kv3bq1dw/

...