Окно поиска jQuery, результаты поиска не соответствуют вводу - PullRequest
2 голосов
/ 28 февраля 2012

Во-первых, название было лучшим, которое я мог придумать.

Я написал очень короткий маленький скрипт для поиска в реальном времени.

Основы этого:

(function ($) {
    $.fn.SearchThing = function (options) {
        options = $.extend({
            MaxCount: 5,
            inputField: '#search_input',
            sugestBox: '#search_sugest'
        }, options);

        var input = $(options.inputField);
        var sugest = $(options.sugestBox);
        sugest.hide();

        input.keyup(function (e) {
            switch (e.keyCode) {
                //Other keys.
                default:
                    queryServer(this.value);
            }
        });

        function queryServer(value) {
            var url = "/search/get?query=" + value; // value;
            $.getJSON(url, function (result) {
                if (result.Results < 1) {
                    sugest.hide();
                    return;
                }

                sugest.children().each(function (idx, itm) {
                    $(itm).remove();
                });
                sugest.show();

                //Build box.
            }
        };
    };
})(jQuery);

И это почти нормально работает. Есть 2 вещи, которые нужно желать, хотя. Тот, который на самом деле не так важен, а затем другой, который на самом деле является ошибкой, которая может быть решена другим, хотя, я не знаю. Но вот они:

BUG: результаты не всегда совпадают с данными в «поле ввода»

Это означает, что если я набираю «ASD», он выполняет поиск «ASD», поэтому, если я говорю «ASD», за которым следует быстрый «возврат», он должен искать «AS», однако время от времени похоже, что в итоге получаются результаты для "ASD".

Я знаю это, потому что в настоящее время я не реализовал серверную часть поиска, поэтому я возвращаю статический список, в котором первый элемент является поисковым термином.

Я полагаю, что это может быть потому, что поиск "AS" вернулся раньше, чем поиск "ASD", поэтому результаты применяются в порядке -> "A", "AS", "AS", "ASD" где они должны применяться в порядке «A», «AS», «ASD», «AS» ....

Также бывает, что если я наберу "ASD", он будет применять его по порядку -> "A", "ASD", "AS". (То же самое происходит, поиск "ASD" возвращается до поиска "AS")

Примечание: Короткие поисковые термины, такие как "ASD", редко вызывают эту ошибку, более длинные с более быстрым набором текста более вероятны, я использовал короткий здесь, чтобы составить описание проблема проще.

Кто-нибудь может предложить хорошее решение для этого?

DESIRED: небольшая задержка перед отправкой поиска, если нажатия клавиш быстрые, обрабатывается только последнее "значение".

Это может на самом деле решить проблему, описанную выше, на самом деле, скорее всего, так и будет.

Вкратце я посмотрел на «задержку», но поскольку он не может «отменить» выполнение (насколько я понял), для этого потребовалось бы много реализации, как я вижу, но, возможно, у кого-то есть блестящая идея по эта часть.

Иначе у кого-нибудь есть другие идеи, как это сделать?

Ответы [ 3 ]

1 голос
/ 28 февраля 2012

Основываясь на awnser mkilmanas, это то, что сработало:

if (lastTimeout != null) {
    window.clearTimeout(lastTimeout);
}

var value = this.value;
lastTimeout = window.setTimeout(function () {
    queryServer(value);
}, 300); //Choose a bit shorter timeout since 500 actually gave a "clunky" feeling.

за исключением детализации, если поиски отправляются в порядке, скажем «A», затем «AB» (потому что мы печатаем медленно),если для выполнения «A» требуется 1000 мс, а «AB» - только 100 мс, то «A» возвращается позже, чем «AB», и возникает та же проблема.

Я мог бы решить эту проблему, вернув исходный запрос изсервер, а затем добавьте следующую проверку:

        var url = "/search/get?query=" + value; // value;
        $.getJSON(url, function (result) {
            if (result.Results < 1) {
                sugest.hide();
                return;
            }
            if (input.val() != result.Query) {
                return;
            }

Это должно отфильтровать результаты с задержкой по сравнению с более поздними запросами, которые возвращали результаты быстрее, я не могу придумать никаких других последствий этого.

1 голос
/ 29 марта 2012

Полный исходный код для Эдуардо Молтени. Обратите внимание, что это в значительной степени приспособлено к тому, как создается мой сайт и как сервер отвечает на запрос, поэтому он, скорее всего, будет вдохновлять только сервер.

Также обратите внимание, что он предъявляет требования к HTML.

Идея "MyArea" в приведенном ниже коде состоит в том, что я вырезал области, в которых я выполняю поиск, и заменил их наодин «MyArea», это показывает, что он поддерживает отображение сгруппированного набора результатов.

appendSection должен вызываться для каждой области, которую вы хотите, и именно здесь вы бы структурировали HTML, который вы хотели бы получитьиз этого, обратите внимание, что у меня в качестве примера есть «Заголовок» и т. д. Вы не можете этого хотеть.

// Copyright 2012 Jens Melgaard, www.dotjem.com
// Licensed under the Apache License, Version 2.0 (the "License");
// http://www.apache.org/licenses/LICENSE-2.0
(function ($) {
    $.fn.dotJEMSearch = function (options) {
        options = $.extend({
            inputField: '#search_input',
            sugestBox: '#search_sugest'
        }, options);

        var timeout = null;
        var input = $(options.inputField);
        var sugest = $(options.sugestBox);
        var current = -1;
        var displayed = 0;
        var items = [];

        sugest.hide();

        input.blur(function () { sugest.hide(); });
        input.focus(function () { if (displayed > 0) { sugest.show(); } });
        input.keydown(function (e) { if (e.keyCode == 13) e.preventDefault(); });
        input.keyup(function (e) {
            switch (e.keyCode) {
                case 13: //Return Key
                    e.preventDefault();
                    if (current != -1) {
                        window.location.href = items[current].Url;
                    } else {
                        window.location.href = '/search?query=' + this.value;
                    }
                    return false;

                case 38: //up key
                    selectItem(current - 1);
                    return false;

                case 40: //up key
                    selectItem(current + 1);
                    return false;

                default:
                    if (timeout != null) {
                        window.clearTimeout(timeout);
                    }

                    var value = this.value;
                    timeout = window.setTimeout(function () {
                        queryServer(value);
                    }, 200);
            }
        });

        function queryServer(value) {
            timeout = null;

            var url = "/search/get?query=" + value;
            $.getJSON(url, function (result) {
                items = [];
                displayed = 0;
                if (result.Results < 1) {
                    sugest.hide();
                    return;
                }
                if (input.val() != result.Query) {
                    return;
                }

                sugest.children().each(function (idx, itm) {
                    $(itm).remove();
                });
                sugest.show();
                appendSection('Search Results', result.MyArea);
            });
        };

        function appendSection(heading, elements) {
                    if (elements.Count > 0) {
            var show = elements.Items.length;
            sugest.append('<h1>' + heading + '<em>' + show + ' of ' + elements.Count + '</em></h1>');

            var elm = $('<ul>');
            for (var i = 0; i < show; i++) {
                var item = elements.Items[i];
                var listElm = $('<li><a href="' + item.Href + '">' + item.Title + '</a></li>');

                (function (index) {
                    listElm.hover(function () { selectItem(index); }, function () { deselect(); });
                })(displayed);
                items[displayed++] = { Elm: listElm, Url: item.Href };
                elm.append(listElm);
            }
            sugest.append(elm);
        };

        function selectItem(idx) {
            deselect();
            current = (idx + items.length) % items.length;
            $(items[current].Elm).addClass('active');
        };

        function deselect() {
            if (current < 0)
                return;
            $(items[current].Elm).removeClass('active');
            current = -1;
        };

    };
})(jQuery);

Часть HTML

                <form id="search" class="search" name="search_form">
                    <input type="text" name="query" autocomplete="off" id="search_input"/>
                    <div id="search_sugest" style="display: none;">
                    </div>
                </form>

    <!-- somewhere at the bottom-->
    <script type="text/javascript">
        $(window).load(function () {
            $('.search').dotJEMSearch();
        });
    </script>

Следующая частькак структурирован формат "JSON"В моем случае это возвращает серверная часть обработчика HTTP (ASP.NET).

@"{  ""Results"": 33,
     ""Query"": """ + query + @""",
     ""MyArea"": {
         ""Count"": 21,
         ""Items"": [
       { ""Title"": ""One"", ""Desc"": ""description"", ""Href"": ""/link"" },
       { ""Title"": ""Two"", ""Desc"": ""description"", ""Href"": ""/link"" },
       { ""Title"": ""Three"", ""Desc"": ""description"", ""Href"": ""/link"" },
       { ""Title"": ""Four"", ""Desc"": ""description"", ""Href"": ""/link"" },
       { ""Title"": ""Five"", ""Desc"": ""description"", ""Href"": ""/link"" }
                    ]
               }
  }";
1 голос
/ 28 февраля 2012

Причина всего этого заключается в том, что запрос-ответ занимает больше времени, чем при следующем нажатии клавиши, поэтому отображаются предыдущие результаты.

Я думаю, вы сможете исправить обе "проблемы" с помощью одного трюка:

var delayTime = 500;
var lastTimeout = null;
var input = $(options.inputField);
var sugest = $(options.sugestBox);
sugest.hide();

input.keyup(function (e) {
    switch (e.keyCode) {
        //Other keys.
        default:
            if (lastTimeout != null) {
                clearTimeout(lastTimeout);
            }
            lastTimeout = setTimeout('queryServer("'+this.value+'")', delayTime);
    }
});

function queryServer(value) {
    lastTimeout = null;
    // ... all the rest as before ...
};

Это отобразит подсказки только через 0,5 секунды после того, как вы перестанете печатать (или сделаете паузу так долго).

...