代码之家  ›  专栏  ›  技术社区  ›  Tarasovych

Vue autocomplete元素-跟踪输入更改的问题

  •  0
  • Tarasovych  · 技术社区  · 6 年前

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

    <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 再次获取数据, <数据列表> 再次刷新。

    如何防止触发 @input 在我选择了建议之后?现在我要点击两次。

    我试着绑起来 @click < <option> 但没用。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Sølve T. DisgruntledGoat    6 年前

    这么简单但是 黑的 解决此问题的方法是,如果event.data未定义,则返回:

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

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

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

      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>
        2
  •  1
  •   Tarasovych    6 年前

    这对我来说很管用。非常感谢 Sølve Tornøe .

    我开始调查 InputEvent 一旦触发,就会出现 inputType: insertText 里面 对象。
    当通过单击更改输入值时 <datalist> 选项,则事件对象中不存在此类字段,而事件实际上是 Event 输入事件

    在模板中,我们必须添加事件参数来传递: @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
    }
    

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