【发布时间】:2012-07-09 10:19:28
【问题描述】:
是否有不依赖于任何其他库的 javascript 自动完成库?
我没有使用 jQuery 或类似的东西,因为我正在制作一个需要保持额外光线的移动应用程序。
【问题讨论】:
-
@PeterAjtai 此链接已损坏。
是否有不依赖于任何其他库的 javascript 自动完成库?
我没有使用 jQuery 或类似的东西,因为我正在制作一个需要保持额外光线的移动应用程序。
【问题讨论】:
对于 2017 年以后需要简单解决方案的任何人,您可以使用 HTML5 的内置 <datalist> 标签,而不是依赖 JavaScript。
例子:
<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">
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
【讨论】:
前天晚上我正在研究这个,我的解决方案原来是这里的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', },
]
你可以看到它在搜索词和option.first_name都小写后基于this.searchTerms进行过滤,但是搜索option.user.first_name太死板了。我最初的尝试是通过字段进行过滤,例如:
this.field = 'user.first_name';
但这涉及到处理 this.field.split('.') 之类的野蛮自定义 JavaScript 并动态生成过滤器函数。
相反,我记得我之前使用过的一个旧库 fuse.js,它运行良好,因为它不仅可以处理我刚刚称为 this.field 的任意嵌套的情况,还可以处理基于定义的阈值。
在这里查看:https://fusejs.io/
[编辑说明]:我意识到这个问题是在寻找 no-external-library,但我想把这篇文章保留在这里,因为它提供了相邻的值。它并非旨在成为“解决方案”。
这是我目前的使用方式:
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] 部分很重要,因为您可以在此处传递要搜索的键,并且可以传递它们的数组。例如,您可以通过keys: ['user.first_name', 'user.friends.first_name'] 过滤this.data。
我目前在 Vue JS 中使用它,所以我在实例 watch 函数中有上述逻辑,所以每次 this.searchTerms 更改时,该逻辑都会运行并更新 this.filteredData,它被放入我的下拉列表中我的自动完成组件。
另外我很抱歉,我刚刚意识到这个问题专门说没有外部库,但我还是会发布这个问题,因为每次我在 Vue JS 或 React JS 中进行 ES6 自动完成时都会发现这个问题。我认为有严格或松散的模糊匹配和支持任意嵌套的数据是非常有价值的。基于 Webpack 包分析器,fuse.js 压缩后为 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() 获取您的数组并返回一个包含匹配项的新数组。
【讨论】:
Here 是一个基本的 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>
【讨论】:
.join('\\w*') 替换为.join('\\w*\\s*\\w*') 可以匹配来自不同单词的字母
ES2016 特性:Array.prototype.includes 没有外部库。
function autoComplete(Arr, Input) {
return Arr.filter(e =>e.toLowerCase().includes(Input.toLowerCase()));
}
【讨论】:
function autoComplete(Arr, Input) { return Arr.filter(e=>e.toLowerCase().indexOf(Input.toLowerCase()) !== -1); }
我通过将 JSON 请求发送回服务器并使用 Python 代码执行自动完成来完成此操作。它有点慢,但它节省了发送大量数据。
【讨论】:
自动完成脚本的核心是对术语字典的 ajax 调用。
我假设您的移动应用程序已经包含一个 ajax 功能,所以您最好还是从头开始编写自动完成功能?基本上你只需要一个输入标签、一个触发 ajax 调用的 keyup 事件处理程序和一个用于收集响应的 div。
[更新] 基于 cmets,来自 John Resig 博客的一些参考资料:
【讨论】: