使用 VueJS 提前输入完整体验
Type ahead complete experience with VueJS
我想创建一个 输入字段,它提供有关完成的建议 比如 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 and the VueJS experience is pretty poor across the board. However it works ok without VueJS.
有什么我遗漏的吗?演示:https://dfts.dabase.com/
也许我需要在 VueJS 中创建自己的下拉菜单 HTML,就像 https://dl.dabase.com/?polyfill=true 中发生的那样?
Chrome
上的性能问题
此处报告 Chrome 存在性能问题:
将解决方案应用于您的 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 创建时间(创建一个片段并且只根据 将其附加到 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/
我想创建一个 输入字段,它提供有关完成的建议 比如 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 and the VueJS experience is pretty poor across the board. However it works ok without VueJS.
有什么我遗漏的吗?演示:https://dfts.dabase.com/
也许我需要在 VueJS 中创建自己的下拉菜单 HTML,就像 https://dl.dabase.com/?polyfill=true 中发生的那样?
Chrome
上的性能问题此处报告 Chrome 存在性能问题:
将解决方案应用于您的 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 创建时间(创建一个片段并且只根据
这里是纯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/