html - 提前输入 VueJS 的完整经验

标签 html vue.js autocomplete datalist

我想创建一个 提供完成建议的输入字段 喜欢什么 VScode“智能感知”(我认为)或喜欢 dmenu做。
我一直在使用 Vue JS 和如下代码:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
    <label>Lookup German word:
        <input type="text" v-model.trim="word" v-on:keyup="signalChange" v-on:change="signalChange" list="words" autofocus>
    </label>
    <datalist id="words">
        <option v-for="w in words">${w}</option>
    </datalist>
    Query: ${query} Results: ${words.length} Time taken: ${fetchtime} ms
</div>

<script>
    const app = new Vue({
        el:'#app',
        delimiters: ['${', '}'],
        data() {
            return {
                listId:'words',
                word:'',
                query:'',
                words:[],
                fetchtime: 0
            }
        },
        methods: {
            async signalChange(){
                console.log(this.word)
                if (this.word.length > 2 && this.word.slice(0,3).toLowerCase() != this.query) {
                    this.query = this.word.slice(0,3).toLowerCase()
                    let time1 = performance.now()
                    let response = await fetch('https://dfts.dabase.com/?q=' + this.query)
                    const words = await response.json()
                    let time2 = performance.now()                    
                    this.fetchtime = time2 - time1
                    this.listId="";
                    this.words = words
                    setTimeout(()=>this.listId="words");
                }
            }
        }
    })
</script>

哪里signalChange将获取一些完成结果。
然而,用户体验 (UX) 是不直观的。键入三个字符(如“for”)后,您必须退格才能看到补全。我已经 tried a couple of browsers VueJS 的体验很差。然而它works ok without VueJS .
有什么我想念的吗?演示:https://dfts.dabase.com/
也许我需要在 VueJS 中创建自己的下拉 HTML,就像在 https://dl.dabase.com/?polyfill=true 中发生的那样?

最佳答案

Chrome 上的性能问题
此处报告了 Chrome 上的性能问题:Is this a Chrome UI performance bug related to input + datalist?
将解决方案应用于您的 Vue 代码对于 Chrome 来说效果很好:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
    <label>Lookup German word:
        <input type="text" v-model.trim="word" v-on:keyup="signalChange" v-on:change="signalChange" list="words" autofocus>
    </label>
    <datalist v-bind:id="listId">
        <option v-for="w in words">${w}</option>
    </datalist>
    Query: ${query} Results: ${words.length} Time taken: ${fetchtime} ms
</div>

<script>
    const app = new Vue({
        el:'#app',
        delimiters: ['${', '}'],
        data() {
            return {
                listId:'words',
                word:'',
                query:'',
                words:[],
                fetchtime: 0
            }
        },
        methods: {
            async signalChange(){
                console.log(this.word)
                if (this.word.length > 2 && this.word.slice(0,3).toLowerCase() != this.query) {
                    this.query = this.word.slice(0,3).toLowerCase()
                    let time1 = performance.now()
                    let response = await fetch('https://dfts.dabase.com/?q=' + this.query)
                    const words = await response.json()
                    let time2 = performance.now()                    
                    this.fetchtime = time2 - time1
                    this.listId="";
                    this.words = words
                    setTimeout(()=>this.listId="words");
                }
            }
        }
    })
</script>

Firefox 仍然无法正常工作,因此请参阅下面我的原始答案:
原答案:
我注意到运行你的代码时有很大的滞后,所以我开始稍微摆弄一下,似乎问题是为大量项目生成数据列表选项。
由于无论如何您只会显示一些结果,因此可以做的是限制渲染选项的数量,然后在添加更多字符时使用过滤器显示更多结果。
这在 Chrome 上运行良好,但在 Firefox 上仍然失败(尽管 Firefox 中存在一个已知问题: https://bugzilla.mozilla.org/show_bug.cgi?id=1474137 )
一探究竟:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <label>Lookup German word:
    <input type="text" v-model="word" v-on:keyup="signalChange"  list="words" autofocus>
  </label>
  <datalist id="words">
    <option v-for="w in words">${w}</option>
  </datalist> Query: ${query} Results: ${fetchedWords.length} Time taken: ${fetchtime} ms
</div>

<script>
  new Vue({
    el: '#app',
    delimiters: ['${', '}'],
    data() {
      return {
        word: '',
        query: '',
        words: [],
        fetchedWords: [],
        fetchtime: 0
      }
    },
    methods: {
      async signalChange() {
        if (this.word.length > 2 && this.word.slice(0, 3).toLowerCase() != this.query) {
          this.query = this.word.slice(0, 3).toLowerCase();
          let response = await fetch('https://dfts.dabase.com/?q=' + this.query);
          this.fetchedWords = (await response.json());
          this.words = this.fetchedWords.slice(0, 10);
        } else if (this.word.includes(this.query)) {
          this.words = this.fetchedWords.filter(w => w.startsWith(this.word)).slice(0, 10);
        } else {
          this.words = [];
        }
      }
    }


  })
</script>

编辑:这只是与 Vue 相关的问题吗?不。
我在纯 JS+HTML 中创建了一个等效的实现。
使用了一种高性能的方式来最小化 DOM 创建时间(创建一个片段,并且按照 How to populate a large datalist (~2000 items) from a dictionary 只将它附加到 DOM 一次),但仍然需要很长时间才能响应。一旦它运行良好,但在我的机器上输入"is"后几乎需要一分钟才能响应。
下面是纯 JS+HTML 的实现:

let word = '';
let query = '';
const input = document.querySelector('input');
const combo = document.getElementById('words');
input.onkeyup = function signalChange(e) {
  word = e.target.value;
  console.log(word)
  if (word.length > 2 && word.slice(0, 3).toLowerCase() != query) {
    query = word.slice(0, 3).toLowerCase();
    fetch('https://dfts.dabase.com/?q=' + query)
      .then(response => response.json())
      .then(words => {
        const frag = document.createDocumentFragment();
        words.forEach(w => {
          var option = document.createElement("OPTION");
          option.textContent = w;
          option.value = w;
          frag.appendChild(option);
        })
        combo.appendChild(frag);
      });
  }
}
<div id="app">
  <label>Lookup German word:
    <input type="text" list="words" autofocus>
  </label>
  <datalist id="words"></datalist>
</div>

因此,考虑到这一点以及由于错误导致的 Firefox 中的有限经验,您应该在没有数据列表的情况下实现自定义自动完成。
为了获得良好的性能,如果列表非常大,您可能希望无论如何都将整个列表保留在 DOM 之外,并在用户更改输入或在列表中滚动时更新它。
以下是使用 OP 示例中的 API 的现有自定义自动完成示例:https://jsfiddle.net/ywrvhLa8/4/

关于html - 提前输入 VueJS 的完整经验,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66621585/

相关文章:

html - 如何在不影响父元素位置的情况下将::before 伪元素放在父元素上方(和旁边)

html - 是否有浏览器/平台怪癖和不一致的数据库/wiki?

vue.js - 模拟tab键

Xcode 3.2.4 代码感知不适用于 UIPopoverController

windows-phone-7 - 使用 Inputscope ="Search"关闭单词建议

html - 损坏的 HTML 表格

java - Spring MVC jsp 对象列表

javascript - webpack - 如何根据需要加载分块的 polyfill 文件

javascript - vue.js 中的 $http.get() 与 axios.get() 有什么区别?

php - 在 php/mysql 不工作的情况下使用 JQuery 自动完成