提前输入完整的 VueJS 体验

Posted

技术标签:

【中文标题】提前输入完整的 VueJS 体验【英文标题】:Type ahead complete experience with VueJS 【发布时间】:2021-06-11 18:01:31 【问题描述】:

我希望创建一个输入字段,以提供有关完成的建议,就像 VScode “Intellisense”(我认为)或 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 中发生的那样?

【问题讨论】:

您与初始化为word 的数据属性和您使用的键值word in words 发生冲突。将其更改为 w in words 并使用 w 而不是 $word 没有区别...不会自动完成 【参考方案1】:

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 一次),但仍然需要很长时间才能做出响应。一旦它运行良好,但在我的机器上输入“was”后几乎需要一分钟才能响应。

这是纯 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/

【讨论】:

IIUC 你只是在减少 DOM 上的结果数量?也许这是一个 VueJS 问题,值得考虑另一种方法? @hendry 是的,我基本上只是在减少 DOM 上的结果数量。但这似乎不是 VueJS 问题 - 检查我的答案上的编辑 关于使用另一种方法 - 是的,绝对 - 正如我在指出 firefox 错误时提到的那样,动态数据列表支持不是很好。除此之外,我建议您通过将结果保存在内存中并根据需要显示来尽可能地保持 DOM。 那么使用选择元素 t 而不是 datalist 提供最好的用户体验? 感谢您为此付出的努力!我将您的建议应用于dfts.dabase.com

以上是关于提前输入完整的 VueJS 体验的主要内容,如果未能解决你的问题,请参考以下文章

免费领取王佩丰老师《Excel表格实战训练营》体验课

完整的用户体验要素包含哪些

新一代数据科学ide平台DataSpell提前发行版体验

深度社区版(Deepin Community) 体验

用户体验--怎样绘制用户体验的地图

VueJS + IDEA + Git