没有外部库的 JavaScript 自动完成
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11404855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript autocomplete without external library
提问by Billy Moon
Is there a javascript autocomplete library that does not depend on any other libraries?
是否有不依赖于任何其他库的 javascript 自动完成库?
I am not using jQuery or the likes as I am making a mobile app that I need to keep extra light.
我没有使用 jQuery 或类似的东西,因为我正在制作一个需要保持额外亮度的移动应用程序。
回答by svnm
Hereis a basic JavaScript example, which could be modified into an autocomplete control:
这是一个基本的 JavaScript 示例,可以将其修改为自动完成控件:
var people = ['Steven', 'Sean', 'Stefan', 'Sam', 'Nathan'];
function matchPeople(input) {
var reg = new RegExp(input.split('').join('\w*').replace(/\W/, ""), 'i');
return people.filter(function(person) {
if (person.match(reg)) {
return person;
}
});
}
function changeInput(val) {
var autoCompleteResult = matchPeople(val);
document.getElementById("result").innerHTML = autoCompleteResult;
}
<input type="text" onkeyup="changeInput(this.value)">
<div id="result"></div>
回答by Optimae
For anyone looking at this in 2017 onwards who needs a simple solution, you can use HTML5's built-in <datalist>
tag instead of relying on JavaScript.
对于 2017 年以后需要简单解决方案的人来说,您可以使用 HTML5 的内置<datalist>
标签而不是依赖 JavaScript。
Example:
例子:
<datalist id="languages">
<option value="HTML">
<option value="CSS">
<option value="JavaScript">
<option value="Java">
<option value="Ruby">
<option value="PHP">
<option value="Go">
<option value="Erlang">
<option value="Python">
<option value="C">
<option value="C#">
<option value="C++">
</datalist>
<input type="text" list="languages">
Note that this won't work in Safari (as of April 2017).
请注意,这在 Safari 中不起作用(截至 2017 年 4 月)。
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
回答by Christophe
The core of an autocomplete script will be the ajax call to the dictionary of terms.
自动完成脚本的核心是对术语字典的 ajax 调用。
I assume your mobile application already includes an ajax function, so maybe you're better off just writing your autocomplete from scratch? Basically all you need in an input tag, a keyup event handler that triggers the ajax call, and a div to collect the response.
我假设您的移动应用程序已经包含一个 ajax 功能,所以也许您最好从头开始编写自动完成功能?基本上所有你需要的输入标签、一个触发 ajax 调用的 keyup 事件处理程序和一个用于收集响应的 div。
[Update] Based on the comments, some references from John Resig's blog:
[更新] 根据评论,John Resig 博客中的一些参考资料:
http://ejohn.org/blog/revised-javascript-dictionary-search/
http://ejohn.org/blog/revised-javascript-dictionary-search/
回答by ronaldtgi
ES2016 feature: Array.prototype.includes
without external library.
ES2016 特性:Array.prototype.includes
无需外部库。
function autoComplete(Arr, Input) {
return Arr.filter(e =>e.toLowerCase().includes(Input.toLowerCase()));
}
回答by agm1984
I was researching this the other night, and my solution was originally like the ES6 solution in here, like this:
前几天我正在研究这个,我的解决方案最初就像这里的 ES6 解决方案,像这样:
return this.data.filter((option) => {
return option.first_name
.toString()
.toLowerCase()
.indexOf(this.searchTerms.toLowerCase()) >= 0
})
But the problem with that is it isn't robust enough to handle filtering nested data. You can see it is filtering this.data
which has a data structure like:
但问题是它不够健壮,无法处理过滤嵌套数据。您可以看到它正在过滤this.data
,它具有如下数据结构:
[
{ first_name: 'Bob', },
{ first_name: 'Sally', },
]
You can see it filters based on this.searchTerms
after lowercasing both the search term and option.first_name
, but it is too rigid to search for option.user.first_name
. My original attempt was to pass in the field to filter by, such as:
this.searchTerms
在将搜索词 和 都小写后,您可以看到它基于过滤器进行过滤option.first_name
,但它太死板而无法搜索option.user.first_name
。我最初的尝试是通过字段进行过滤,例如:
this.field = 'user.first_name';
But this involves savage, custom JavaScript to handle something like this.field.split('.')
and dynamically generating the filter function.
但这涉及野蛮的、自定义的 JavaScript 来处理类似this.field.split('.')
和动态生成过滤器功能的事情。
Instead, I remembered an old library I've used before called fuse.js
, and it is working well because it not only handles that case of arbitrary nesting on what I just called this.field
but also handles fuzzy matching based on defined thresholds.
相反,我想起了我之前使用过的一个名为 的旧库fuse.js
,它运行良好,因为它不仅可以处理我刚刚调用的任意嵌套的情况,this.field
还可以处理基于定义阈值的模糊匹配。
Check out here: https://fusejs.io/
在这里查看:https: //fusejs.io/
[edit note]: I realize this question is looking for no-external-library, but I want to keep this post here as it provides adjacent value. It is not intended to be "the" solution.
[编辑说明]:我意识到这个问题正在寻找 no-external-library,但我想把这篇文章保留在这里,因为它提供了相邻的价值。它不打算成为“解决方案”。
Here is how I'm currently using it:
这是我目前使用它的方式:
import Fuse from 'fuse.js';
const options = {
threshold: 0.3,
minMatchCharLength: 2,
keys: [this.field],
};
const fuse = new Fuse(this.data, options);
this.filteredData = fuse.search(this.searchTerms);
You will have to read the Fuse docs to understand that better, but fundamentally, you can see that a new Fuse()
object is created using the data to filter and the options.
您必须阅读 Fuse 文档才能更好地理解这一点,但从根本上说,您可以看到new Fuse()
使用要过滤的数据和选项创建了一个对象。
The keys: [this.field]
part is important because that's where you pass in the keys to search by, and you can pass in an array of them. For example, you could filter this.data
by keys: ['user.first_name', 'user.friends.first_name']
.
这keys: [this.field]
部分很重要,因为这是您传递要搜索的键的地方,并且您可以传递它们的数组。例如,您可以过滤this.data
通过keys: ['user.first_name', 'user.friends.first_name']
。
I am using this currently in Vue JS, so I have that above logic inside an instance watch
function, so every time this.searchTerms
changes, that logic runs and updates this.filteredData
which is placed into my dropdown list in my autocomplete component.
我目前在 Vue JS 中使用它,所以我在一个实例watch
函数中有上面的逻辑,所以每次this.searchTerms
更改时,该逻辑都会运行并更新this.filteredData
,并将其放入我的自动完成组件的下拉列表中。
Also I'm sorry I just realized this question specifically says without an external library, but I'll post this anyway because I find this question every time I make an ES6 autocomplete in Vue JS or React JS. I think it is very valuable to have strict or loose fuzzy matching and to support arbitrarily nested data. Based on Webpack bundle analyzer, fuse.js
is 4.1kb gzipped, so it is quite small given that it can support "all" client-side filtering needs.
另外我很抱歉,我刚刚意识到这个问题专门说没有外部库,但无论如何我都会发布这个,因为每次我在 Vue JS 或 React JS 中创建 ES6 自动完成时我都会发现这个问题。我认为严格或松散的模糊匹配和支持任意嵌套数据是非常有价值的。基于 Webpack 包分析器,fuse.js
gzipped 为 4.1kb,因此它非常小,因为它可以支持“所有”客户端过滤需求。
If you are limited in your ability to use external libraries, consider my first example piece of code. It works if your data structure is static, and you can easily change option.first_name
to something like option[this.field]
if you wish to variablize the searched field (ie: if your objects are always flat).
如果您使用外部库的能力有限,请考虑我的第一个示例代码。如果您的数据结构是静态的,它就可以工作,并且您可以轻松地更改option.first_name
为类似的内容,option[this.field]
如果您希望对搜索字段进行变量化(即:如果您的对象始终是扁平的)。
You could variablize the list to search as well. Try something like this:
您也可以对要搜索的列表进行变量化。尝试这样的事情:
const radicalFilter = ({ collection, field, searchTerms }) => {
return collection.filter((option) => {
return option[field]
.toString()
.toLowerCase()
.indexOf(searchTerms.toLowerCase()) >= 0
})
}
radicalFilter({
collection: [{ first_name: 'Bob' }, { first_name: 'Sally' }],
field: 'first_name',
searchTerms: 'bob',
})
Based on my experiences over the past couple years, the above sample is very performant. I've used it to filter 10,000 records in a react-table
component, and it didn't break a sweat. It doesn't create any extra intermediate data structures. It is simply just Array.prototype.filter()
which takes your array and returns a new array with matched items.
根据我过去几年的经验,上述示例的性能非常好。我已经用它过滤了一个react-table
组件中的10,000 条记录,它并没有出汗。它不会创建任何额外的中间数据结构。它只是简单地Array.prototype.filter()
获取您的数组并返回一个包含匹配项的新数组。
回答by Ben
I did this once by sending a JSON request back to the server and using Python code to do the autocomplete. It Was a little slow, but it saved sending a ton of data across.
我通过将 JSON 请求发送回服务器并使用 Python 代码执行自动完成来完成此操作。它有点慢,但它节省了发送大量数据。