我最近试图在一些真实世界的应用程序中重用我的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了很多,并且没有得出结论为什么会发生这种情况和/或如何解决这个问题。
任何帮助是极大的赞赏。
我不确定你到底想要做什么,但我的猜测是你两次开始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"
}
]
}
})
在询问了我的一些朋友之后,人们发现“改变”触发器必须在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,它更清洁。我现在正在使用它,但我也留下了问题的原始答案,以防有人需要它。
对于现在遇到这种情况的人来说,这是让它只发射一次的正确方法。
<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>