一个jQuery搜索框,搜索结果与输入不匹配

一个jQuery搜索框,搜索结果与输入不匹配,jquery,ajax,json,delay,Jquery,Ajax,Json,Delay,首先,这个标题是我能想到的最好的 我写了一个非常简短的脚本来执行实时搜索 它的基础是: (function ($) { $.fn.SearchThing = function (options) { options = $.extend({ MaxCount: 5, inputField: '#search_input', sugestBox: '#search_sugest' },

首先,这个标题是我能想到的最好的

我写了一个非常简短的脚本来执行实时搜索

它的基础是:

(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);
(函数($){
$.fn.SearchThing=函数(选项){
选项=$。扩展({
最大计数:5,
inputField:“#搜索_输入”,
建议框:“#搜索建议”
},选项);
变量输入=$(options.inputField);
var sugest=$(options.sugestBox);
sugest.hide();
输入键控(功能(e){
开关(如钥匙代码){
//其他钥匙。
违约:
queryServer(this.value);
}
});
函数查询服务器(值){
var url=“/search/get?query=“+value;//value;
$.getJSON(url、函数(结果){
if(result.Results<1){
sugest.hide();
返回;
}
sugest.children().each(函数(idx、itm){
$(itm.remove();
});
sugest.show();
//构建框。
}
};
};
})(jQuery);
这几乎可以很好地发挥作用。但有两件事需要改进。一件不是很重要,另一件实际上是一个bug,我不知道另一件可能会解决。但它们是:

错误:结果并不总是与“输入字段”中的内容匹配 这意味着,如果我键入“ASD”,它将执行“ASD”搜索,因此,如果我说键入“ASD”,然后快速“退格”,它将搜索“AS”,但有时它似乎会以“ASD”的结果结束

我知道这一点,因为我目前还没有实现搜索后端,所以我返回一个静态列表,其中第一个元素是搜索词

我认为这可能是因为搜索“AS”比搜索“ASD”返回得更快,因此结果按顺序应用—>“A”、“AS”、“AS”、“ASD”,它们应按顺序“A”、“AS”、“ASD”、“AS”应用

如果我输入“ASD”,它也会按照->A”,“ASD”,“AS”的顺序应用它。(同样的情况,搜索“ASD”会在搜索“AS”之前返回)

注意:像“ASD”这样的短搜索词很少触发此错误,长搜索词和快速键入更容易触发此错误,我在这里使用短搜索词使问题描述更容易

有人能提出一个好的解决方案吗

期望:在提交搜索之前有一个小的延迟,如果击键很快,则只处理最后一个“值”。 这实际上可能会解决上述问题,我认为很有可能这样做

我很快就看过了“延迟”,但因为它不能“取消”执行(据我所知),所以我认为它需要分配实现,但也许有人在这方面有一个绝妙的想法


否则,是否有人对如何执行此操作有任何其他想法?

所有这些的原因是请求-响应比下一次按键花费的时间更长,因此会显示以前的结果

我认为您应该能够用一个技巧解决这两个“问题”:

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秒显示建议。

基于mkilmanas的awnser,这是有效的:

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;
            }
var url=“/search/get?query=“+value;//value;
$.getJSON(url、函数(结果){
if(result.Results<1){
sugest.hide();
返回;
}
if(input.val()!=result.Query){
返回;
}

这应该会过滤掉延迟的结果,而不是稍后更快地返回结果的查询,我想不出这样做的任何其他含义。

Eduardo Molteni的完整源代码,请注意,这在很大程度上是根据我的站点的构建方式和服务器对查询的响应方式定制的,因此它很可能只会是一个服务器这是一个灵感

还请注意,它将对HTML的要求放在后面

下面代码中的“MyArea”背后的想法是因为我已经删除了我在其中执行搜索的区域,并将其替换为单个“MyArea”,这是为了表明它支持显示一组分组的结果

appendSection应该为您想要的每个区域调用,这是您想要从中构造HTML的地方,请注意,作为一个示例,我有一个“Header”等。您可能不想这样做

// 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);

干杯,但它似乎不起作用…但这完全是我自己的错,我在代码中遗漏了一些我认为不必要的东西,但是,因为这不起作用,它可能是?…我编辑了原始示例。我猜设置超时中给出的“字符串”只是弄乱了一些东西。因为它是“内部的”函数…或者我们在JS中可能称之为什么???或者我必须将其重写为“public”…(根据jQuery插件指南)现在这是一个范围问题(这在问题的初始公式中并不明显)-超时将在全局范围上调用,因此您需要在某个地方使用对象引用(仅将函数暴露于全局范围是不够的,因为您在函数内部使用了局部'suggest'变量)没关系。我找到了如何让它工作。我会用细节来回答,因为代码注释非常混乱。所以谢谢。不,我知道,这就是为什么我说这完全是我自己的错…这意味着你的答案在未来是好的
                <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>
@"{  ""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"" }
                    ]
               }
  }";