是否有一个不依赖于任何其他库的javascript自动完成库?
我没有使用 jQuery 或类似的东西,因为我正在制作一个移动应用程序,我需要保持额外的轻便。
这里是一个基本的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>
对于任何在 2017 年开始关注此问题并需要简单解决方案的人来说,您可以使用 HTML5 的内置
<datalist>
标签,而不是依赖 JavaScript。
示例:
<datalist id="languages">
<option value="HTML"></option>
<option value="CSS"></option>
<option value="JavaScript"></option>
<option value="Java"></option>
<option value="Ruby"></option>
<option value="PHP"></option>
<option value="Go"></option>
<option value="Erlang"></option>
<option value="Python"></option>
<option value="C"></option>
<option value="C#"></option>
<option value="C++"></option>
</datalist>
<input type="text" list="languages">
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
自动完成脚本的核心是对术语词典的 ajax 调用。
我假设您的移动应用程序已经包含 ajax 功能,所以也许您最好从头开始编写自动完成功能?基本上,您所需要的一切都在一个输入标记、一个触发 ajax 调用的 keyup 事件处理程序以及一个用于收集响应的 div 中。
[更新]根据评论,参考了 John Resig 的博客:
ES2016 功能:
Array.prototype.includes
无需外部库。
function autoComplete(Arr, Input) {
return Arr.filter(e =>e.toLowerCase().includes(Input.toLowerCase()));
}
前几天晚上我正在研究这个问题,我的解决方案最初就像这里的 ES6 解决方案,如下所示:
return this.data.filter((option) => {
return option.first_name
.toString()
.toLowerCase()
.indexOf(this.searchTerms.toLowerCase()) >= 0
})
但问题是它不够强大,无法处理过滤嵌套数据。你可以看到它正在过滤
this.data
,其数据结构如下:
[
{ first_name: 'Bob', },
{ first_name: 'Sally', },
]
在小写搜索词和
this.searchTerms
后,您可以看到它基于 option.first_name
进行过滤,但搜索 option.user.first_name
太严格了。我最初的尝试是传入字段进行过滤,例如:
this.field = 'user.first_name';
但这涉及野蛮的自定义 JavaScript 来处理类似
this.field.split('.')
的事情并动态生成过滤器函数。
相反,我记得我之前使用过一个名为
fuse.js
的旧库,它运行良好,因为它不仅可以处理我刚才所说的 this.field
上的任意嵌套情况,而且还可以根据定义的阈值处理模糊匹配.
在这里查看:https://fusejs.io/
[编辑说明]:我意识到这个问题正在寻找无外部库,但我想将这篇文章保留在这里,因为它提供了相邻的值。它并不是“唯一”的解决方案。
这是我目前的使用方式:
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);
您必须阅读 Fuse 文档才能更好地理解这一点,但从根本上讲,您可以看到使用要过滤的数据和选项创建了一个
new Fuse()
对象。
keys: [this.field]
部分很重要,因为这是您传递搜索键的地方,并且您可以传递它们的数组。例如,您可以按 this.data
过滤 keys: ['user.first_name', 'user.friends.first_name']
。
我目前在 Vue JS 中使用这个,所以我在实例
watch
函数中具有上述逻辑,所以每次 this.searchTerms
更改时,该逻辑都会运行并更新 this.filteredData
,它被放入自动完成的下拉列表中组件。
另外,我很抱歉,我刚刚意识到这个问题专门说没有外部库,但无论如何我都会发布这个问题,因为每次我在 Vue JS 或 React JS 中进行 ES6 自动完成时都会发现这个问题。我认为严格或宽松的模糊匹配以及支持任意嵌套数据是非常有价值的。基于 Webpack 捆绑分析器,
fuse.js
经过 gzip 压缩后大小为 4.1kb,因此它非常小,因为它可以支持“所有”客户端过滤需求。
如果您使用外部库的能力有限,请考虑我的第一个示例代码。如果您的数据结构是静态的,它就可以工作,并且如果您希望改变搜索字段(即:如果您的对象始终是平坦的),您可以轻松地将
option.first_name
更改为 option[this.field]
之类的内容。
您也可以改变搜索列表。尝试这样的事情:
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',
})
根据我过去几年的经验,上面的示例非常高效。我已经用它在
react-table
组件中过滤了 10,000 条记录,而且效果并不差。它不会创建任何额外的中间数据结构。它只是 Array.prototype.filter()
获取您的数组并返回一个包含匹配项的新数组。
我通过将 JSON 请求发送回服务器并使用 Python 代码进行自动完成来完成了一次。虽然有点慢,但它节省了发送大量数据的时间。