如何用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>