如何用vue区分用户输入和数据变化-select
How to differentiate between user input and data change with vue-select
我在我的应用程序中使用 vue-select 并试图阻止事件处理程序在默认值首次加载到 vue-select 输入时触发。
组件如下所示:
<v-select
multiple
v-model="product.recommended_accessories"
label="name"
:options="accessoryOptions"
@input="saveProduct"
@search="onAccessorySearch">
<template slot="option" slot-scope="option">
<h4>{{ option.name }}</h4>
<h5>{{ option.sku }}</h5>
</template>
</v-select>
如您所见,我想在用户更改此 multi-select 中的值时保存产品。它工作正常,但有一个问题。
select 的值与 product.recommended_accessories
数据相关联。在应用程序的其他地方,产品从服务器加载,其中包含 recommended_accessories
属性。加载产品然后触发 saveProduct
被调用,因为 vue-select 为输入设置了预先 selected 选项,这显然会触发 @input
事件。
这附近有没有?也许我在这里犯了某种设计错误。或者我应该使用一个挂钩来绑定事件处理程序,或者设置某种标志,指示产品正在加载并且不应保存产品。
我只是想避免在产品加载后无缘无故地立即保存它。
现在我只跟踪一个 accessoryEventCount
变量,每当加载产品时该变量都会初始化为 0。然后我在 v-select input
事件上调用 saveProduct
之前确保 accessoryEventCount > 0
。
有效,但我仍然想知道是否有更优雅的解决方案。
更新
看起来 Vue.nextTick
正是我要找的。在代码中设置 product 的值之前,我设置了一个标志 this.isSettingProduct = true
。然后我设置产品,然后调用 Vue.nextTick(() => { this.isSettingProduct = false });
.
现在如果 this.isSettingProduct == true
我可以避免保存产品。使用 Vue.nextTick
可确保在异步数据更新完成之前不会将该标志设置回 false。
看起来你应该绑定 prop=onChange,尽管 @input 似乎仍然有效(检查 v-select github: line# 544)。
下面是我的解决方案,在加载你的产品之前,将onChange与function () {}
绑定,加载后,将其与你喜欢的功能绑定。
Vue.component('v-select', VueSelect.VueSelect)
app = new Vue({
el: "#app",
data: {
accessoryOptions: [
{'name':'a1', 'sku':'a2'},
{'name':'b1', 'sku':'b2'},
{'name':'c1', 'sku':'c2'}
],
product: {
recommended_accessories: []
},
saveProduct: function (){}
},
methods: {
onAccessorySearch: function () {
console.log('emit input')
},
loadProduct: function () {
this.product.recommended_accessories = ['a1', 'b1'] // simulate get data from the server
setTimeout( () => {
this.saveProduct = (value) => {
console.log('emit input', this.product.recommended_accessories)
}
}, 400)
}
}
})
#app {
width: 400px;
}
<script src="https://unpkg.com/vue@latest"></script>
<script src="https://unpkg.com/vue-select@latest"></script>
<div id="app">
<button @click="loadProduct()">Click Me!</button>
<v-select
multiple
v-model="product.recommended_accessories"
label="name"
:options="accessoryOptions"
:on-change="saveProduct"
@search="onAccessorySearch">
<template slot="option" slot-scope="option">
<span>{{ option.name }}</span>
<span>{{ option.sku }}</span>
</template>
</v-select>
</div>
我在我的应用程序中使用 vue-select 并试图阻止事件处理程序在默认值首次加载到 vue-select 输入时触发。
组件如下所示:
<v-select
multiple
v-model="product.recommended_accessories"
label="name"
:options="accessoryOptions"
@input="saveProduct"
@search="onAccessorySearch">
<template slot="option" slot-scope="option">
<h4>{{ option.name }}</h4>
<h5>{{ option.sku }}</h5>
</template>
</v-select>
如您所见,我想在用户更改此 multi-select 中的值时保存产品。它工作正常,但有一个问题。
select 的值与 product.recommended_accessories
数据相关联。在应用程序的其他地方,产品从服务器加载,其中包含 recommended_accessories
属性。加载产品然后触发 saveProduct
被调用,因为 vue-select 为输入设置了预先 selected 选项,这显然会触发 @input
事件。
这附近有没有?也许我在这里犯了某种设计错误。或者我应该使用一个挂钩来绑定事件处理程序,或者设置某种标志,指示产品正在加载并且不应保存产品。
我只是想避免在产品加载后无缘无故地立即保存它。
现在我只跟踪一个 accessoryEventCount
变量,每当加载产品时该变量都会初始化为 0。然后我在 v-select input
事件上调用 saveProduct
之前确保 accessoryEventCount > 0
。
有效,但我仍然想知道是否有更优雅的解决方案。
更新
看起来 Vue.nextTick
正是我要找的。在代码中设置 product 的值之前,我设置了一个标志 this.isSettingProduct = true
。然后我设置产品,然后调用 Vue.nextTick(() => { this.isSettingProduct = false });
.
现在如果 this.isSettingProduct == true
我可以避免保存产品。使用 Vue.nextTick
可确保在异步数据更新完成之前不会将该标志设置回 false。
看起来你应该绑定 prop=onChange,尽管 @input 似乎仍然有效(检查 v-select github: line# 544)。
下面是我的解决方案,在加载你的产品之前,将onChange与function () {}
绑定,加载后,将其与你喜欢的功能绑定。
Vue.component('v-select', VueSelect.VueSelect)
app = new Vue({
el: "#app",
data: {
accessoryOptions: [
{'name':'a1', 'sku':'a2'},
{'name':'b1', 'sku':'b2'},
{'name':'c1', 'sku':'c2'}
],
product: {
recommended_accessories: []
},
saveProduct: function (){}
},
methods: {
onAccessorySearch: function () {
console.log('emit input')
},
loadProduct: function () {
this.product.recommended_accessories = ['a1', 'b1'] // simulate get data from the server
setTimeout( () => {
this.saveProduct = (value) => {
console.log('emit input', this.product.recommended_accessories)
}
}, 400)
}
}
})
#app {
width: 400px;
}
<script src="https://unpkg.com/vue@latest"></script>
<script src="https://unpkg.com/vue-select@latest"></script>
<div id="app">
<button @click="loadProduct()">Click Me!</button>
<v-select
multiple
v-model="product.recommended_accessories"
label="name"
:options="accessoryOptions"
:on-change="saveProduct"
@search="onAccessorySearch">
<template slot="option" slot-scope="option">
<span>{{ option.name }}</span>
<span>{{ option.sku }}</span>
</template>
</v-select>
</div>