我正试图在jQuery:中创建一个搜索函数
$('input').on('keyup', function(){
var searchTerm = $("input").val().toLowerCase();
$('.item').each(function(){
if ($(this).filter('[data-text *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
});
每次用户输入时,都会将其与.item
div的数据属性值进行比较。如果该元素的数据属性包含搜索查询,它就会被显示,否则就会被隐藏。
这在Chrome中运行得很好,但在Safari中由于某种原因,当用户输入时,它确实很滞后。
有办法解决这个问题吗?
大约有1400个div(.item
),每个元素的data-text
属性只有大约10-20个字符
编辑,通过删除.show()
和.hide()
并替换为本地Javascript 修复
解决方案
我以前也遇到过类似的问题,我想你可能想尝试添加一个名为";去跳动";,这基本上在进行任何处理之前增加了延迟。在keyup
的情况下,它将等待用户在任何设定的时间内停止键入(比如0.5秒),然后执行该过程(搜索或其他)。如果不使用debounce,它将在用户每次触发keyup
事件时执行搜索。
你可以搜索关于如何做debounce的文章,我想有很多。但本质上它使用了JS 的setTimeout
和clearTimeout
函数
以下是我发现的第一篇文章:https://levelup.gitconnected.com/debounce-in-javascript-improve-your-applications-performance-5b01855e086
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
如何使用此功能?简单地说,只需将实际函数(搜索函数)添加为第一个参数,并在第二个参数中添加延迟(微秒),然后使用.call()函数(为什么要这样做?因为debounce会返回一个函数)。所以我猜是这样的:
$('input').on('keyup', function(){
var searchTerm = $("input").val().toLowerCase();
debounce(function(){
$('.item').each(function(){
if ($(this).filter('[data-text *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
}, 500).call();
});
这就是我要做的,因为这样我就可以在keyup事件中添加一些debounce之外的东西,但你可以把debounce返回的函数放在一个变量中,然后把它与keyup绑定(就像在文章中一样),或者直接把debouce放在keyup内部,就像这样:
$('input').on('keyup', debounce(function(){
...
},500));
它是如何工作的
你可以在文章中阅读它们,或者在StackOverflow中找到答案,这是我得到的;去跳动";Javascript 中的函数
但如果我用我自己的话来说,基本上你首先需要理解的是setTimeout
在调用函数之前设置一个计时器,clearTimeout
取消该计时器。现在在debounce中,你可以看到在任何setTimeout
之前都有一个clearTimeout
。因此,每次触发keyup事件时,它基本上都会取消上次设置的超时(如果有的话),然后再设置一个新的超时。本质上,它会将计时器重置为每次触发事件时设置的值。
例如:
- 用户想要搜索";abc">
- 他们键入";a"->debounce在调用实际搜索";a">
- 在500ms结束之前;b";,所以去跳动消除了";a";搜索和搜索";ab";相反,同时在操作之前设置500毫秒的计时器
- 在500ms结束之前;c";,因此取消";ab";搜索,添加500ms的定时器来搜索";abc">
- 用户停止键入直到500ms结束,现在debounce实际上调用了搜索";abc">
结果是什么?用于搜索的重处理只进行一次;abc";,你也可以在这个繁重的处理中放入一个加载器或其他东西,这样对用户来说会更好
一些快速修复:
- 对div进行排序,然后在
each
之后的单个语句中显示/隐藏,而不是每次迭代
更改DOM的成本相对较高,因此在一条语句中这样做可以大大提高的性能
- 如果这是
table
更改为div
s
表需要对小的更改重新呈现整个表。固定单元格大小会有所帮助。不是这个问题的情况,只是的总体改进
- 使用内存中的过滤器,而不是读取每个项的DOM
读取DOM的速度比在内存中慢得多(当然,在内存中会使用更多的内存)。例如,在.data()
上进行筛选,而不是在内存中使用[data-]
。这在Chrome中可能很快,因为Chrome可能正在缓存[data-
属性,所以在Chrome 中可能没有改进
- 取消对输入事件的抖动,使其仅在用户完成键入时发生
等待,直到用户";成品";键入然后运行操作。
- 使用运算符关联性
虽然是边缘情况,但这条线
if ($(this).filter('[data-text *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1)
即使在searchTerm.length < 1
时也将运行$(this).filter
,更改为
if (searchTerm.length < 1 || $(this).filter('[data-text *= ' + searchTerm + ']').length > 0)
运行示例
function a() { console.log("a"); return true; }
function b() { console.log("b"); return true; } // b() doesn't need to exist
if (a() || b()) console.log("c")
- 考虑服务器端分页/筛选
显著降低了;足迹";在页面上,so将更快/更响应,但检索数据的延迟可能会稍长。根据它的显示方式,1400条记录对用户来说可能是一次查看的大量记录(因此您可以进行筛选)。