提前输入完整的 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 体验的主要内容,如果未能解决你的问题,请参考以下文章