2

我有一个在 DOM 中搜索并在列表中显示结果的 jQuery 脚本。

这里有脚本的简化版本:http: //jsfiddle.net/FuJta/1/

通常有大量结果,因此脚本可能需要一段时间才能执行。(在上面的示例中,这是使用延迟脚本的函数进行模拟的)。因此,如果您在搜索框中输入得太快,脚本会阻止您输入,并且感觉很糟糕。

我怎样才能更改我的脚本,以便您可以自由输入,并在准备好时显示结果。我想要类似 facebook 搜索的东西:如果你输入得太快,结果就会延迟,但你仍然可以输入。

html

<p>Type in foo, bar or baz for searching. It works, but it is quite slow.</p><br/>
<input type="text" id="search"/>

<div id="container" style="display:none">
    <div class="element">foo</div>
    <div class="element">bar</div>
    <div class="element">baz</div>
</div>


<div id="results">
</div>​

Javascript

$(function() {
    function refreshResults() {
        var search = $('#search').val();
        var $filtered = $('#container .element').clone().filter(function() {
            var info = $(this).text();
            return info.toLowerCase().indexOf(search) >= 0;
        });
        $('#results').empty();
        $filtered.each(function() {
            $('#results').append($(this));
        });
    }

    // simulating script delay
    function pausecomp(millis) {
        var date = new Date();
        var curDate = null;
        do {
            curDate = new Date();
        }
        while (curDate - date < millis);
    }

    $('#search').keyup(function() {

        pausecomp(700);
        refreshResults();
    });
});​

一种解决方案可以仅在按 Enter 时刷新结果。这样,搜索结果的延迟感觉还可以。但如果我只是延迟结果并让用户自由输入,我更愿意。

4

3 回答 3

2

您应该使用异步技术执行这样的搜索。毫无疑问,Facebook 使用某种 AJAX 来请求搜索结果——这意味着从服务器获取结果。这将有助于防止您当前遇到的 UI“冻结”。

这是您可以尝试的一个非常简单的示例(它使用 JQuery 来处理 AJAX 请求):

var searchInProgress = false;//used to work out if a search is in progress
var searchInQueue = false;//used to flag if the input data has changed

function getSearchResults(searchText){
    if (searchInProgress ) {
        searchInQueue = true;
        return;
    }

    searchInProgress = true;
    searchInQueue = false;

   $.getJSON("URL",//URL to handle AJAX query
      { searchText: searchText},//URL parameters can go here
      function (data) {
         //handle your returned data here

         searchInProgress = false;

         if (searchInQueue){//text has changed, so search again
            getSearchResults();
         }
      });
}

$('#search').keyup(function() {
        getSearchResults($(this).val());
});

需要注意的几点:处理失败的 AJAX 请求以确保您可以searchInProgress根据需要重置标志可能是一个好主意。此外,您可以根据需要在之后添加延迟keyup,但这完全取决于您希望它如何工作。

于 2012-10-22T09:03:07.573 回答
1

这里有一个解决方案,将搜索过程分成步骤,在过程中将流返回给浏览器以允许 UI 响应。

$(function() {

    function searchFunc($element,search) {
        var info = $element.text();
        return info.toLowerCase().indexOf(search) >= 0;
    }

    var searchProcessor = null;
    function restartSearch() {
        console.log('Restarting...');

        // Clear previous
        if (searchProcessor != null) {
            clearInterval(searchProcessor);
        }
        $('#results').empty();

        // Values for the processor
        var search = $('#search').val();
        var elements = $('#container .element').get();
        console.log('l:',elements,elements.length);

        // Start processing
        searchProcessor = setInterval(function() {
            if (elements.length == 0) {
                // Finished searching all elements
                clearInterval(searchProcessor);
                searchProcessor = null; 
                console.log('Finished.'); 

            } else { 
                console.log('Checking element...'); 
                var $checkElement = $(elements.shift());
                if (searchFunc($checkElement, search)) {
                    $('#results').append($checkElement.clone());
                }
            }
        }, 10);
    }

    $('#search').keyup(function() {
         restartSearch() 
    });
});

它每次只处理一个元素。这可能应该增加,因此它每次可能处理 10 或 100 个,但重要的一点是工作被分成块。

这个解决方案也应该比原来的更快,因为它不是clone()所有的,只有匹配的元素。

于 2012-10-22T09:41:54.870 回答
1

如何在用户键入时延迟 KeyPress 功能,因此它不会为每次击键触发请求?

var timeoutId = 0;
$('#search').keyup(function () { 
    clearTimeout(timeoutId); // doesn't matter if it's 0
    timeoutId = setTimeout(refreshResults, 100);
});

它确实做了我想要的。

于 2012-10-22T09:05:28.147 回答