Vue自动完成元素-跟踪输入更改的问题

时间:2018-10-08 12:38:03

标签: vue.js

我所拥有的:
自动完成元素

<div v-for="(user, index) in users">
    <input v-model="user.name"
           :list="users-autocomplete" @input="autocompleteUser(user.name, index)"/>
    <datalist :id="users-autocomplete">
        <option v-for="user in usersAutocomplete" v-bind:value="user.name"
                v-bind:label="user.name"></option>
    </datalist>
</div>

数据

data() {
    return {
        users: [{
            name: ''
        }]

        usersAutocomplete: []
    }
},

方法

async autocompleteUser(value, index) {
    let that = this
    await axios.get(//fetching data)
        .then(response => {
            that.usersAutocomplete = response.data
        })
}

问题与使用流程有关:

  1. 我开始输入输入内容
  2. autocompleteUser()将一些数据放入usersAutocomplete,而不是<datalist>
  3. 我看到一个自动完成建议,然后单击它。
  4. 输入内容已根据我的选择更改
    @input="autocompleteUser(user.name, index)"又被解雇了!
    因此axios再次获取数据,<datalist>再次刷新。

选择建议后,如何防止触发@input?现在,我必须单击两次。

我试图将@click绑定到<datalist><option>上,但是没有用。

2 个答案:

答案 0 :(得分:1)

似乎,如果对event.data进行类型检查,如果输入事件由数据列表触发,则返回undefined。为什么会这样,我目前不知道。

因此解决此问题的一种简单但 hacky 方法可能是如果event.data未定义,则返回:

if(event.data === undefined) return;

我在发表评论后意识到您有很多用户。因此,除非您进行大量循环,否则观察者将无法正常工作。

请注意,我无法解释此解决方案,并且从未使用过dataLists,因此不能保证这是一个好的解决方案。

编辑:通过添加一些逻辑,您可以以编程方式模糊输入元素,这将导致删除该选项:

  if(e.data === undefined) {
    const allUserNames = this.usersAutocomplete.map(user => user.name)
    if(allUserNames.includes(value))
      this.$refs.myInput[0].blur();
    return
   }

new Vue({
  el: '#vue',
  data() {
      return {
          users: [{
              name: ''
          }],

          usersAutocomplete: []
      }
  },
  methods: {
    autocompleteUser(e, value, index) {
      if(e.data === undefined) {
        const allUserNames = this.usersAutocomplete.map(user => user.name)
        if(allUserNames.includes(value))
          this.$refs.myInput[0].blur();
        return
       }
      this.dummyAsync()
          .then(response => {
            console.log("autocompleteUser executed")
            this.usersAutocomplete = response
          })
    },
    dummyAsync() {
      const data = [
        {name: 'John Doe'},
        {name: 'Jane Doe'},
        {name: 'Bobby Doe'}
      ]
      return new Promise(resolve => {
        setTimeout(function() {
          resolve(data);
        }, 400); //Wannabe network delay
      });
    }
  }
})

Vue.config.productionTip = Vue.config.devtools = false
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<main id="vue">
  <div v-for="(user, index) in users">
      <input v-model="user.name"
             list="usersAutocomplete"
             ref="myInput"
             @input="autocompleteUser($event, user.name, index)"
      />
      <datalist id="usersAutocomplete">
          <option v-for="user in usersAutocomplete"
                  :value="user.name"
                  :label="user.name"
          />
      </datalist>
  </div>
</main>

答案 1 :(得分:1)

这现在对我有用。非常感谢Sølve Tornøe

我开始调查InputEvent。我发现一件事:在输入中键入内容时,会触发InputEventinputType: insertText对象中有一个InputEvent
通过单击<datalist>选项更改输入值时,事件对象中不存在此类字段,并且事件实际上是Event,而不是InputEvent

在模板中,我们必须添加事件参数以通过:@input="autocompleteUser($event, user.nickname, index)"

比相应的更改方法:

async autocompleteUser(e, value, index) {
    if (e.inputType !== 'insertText') {
        //input value is modified not by typing in the input
        //so we can clear our data source, used for datalist
        this.usersAutocomplete = []
        return
    }
    let that = this
    await axios.get(//fetching data)
        .then(response => {
            that.usersAutocomplete = response.data
        })
}

UPD:由于以下原因在Firefox中不起作用

if (e.inputType !== 'insertText') {
    this.usersAutocomplete = []
    return
}

UPD2:修复

if (e.constructor.name !== 'InputEvent') {
  this.usersAutocomplete = []
  return
}