javascript - 自动建议下拉菜单不使用向上/向下箭头键选择

标签 javascript php jquery ajax

我的网站有一个非常基本的自动建议功能,只要用户在我的搜索输入中输入内容,它就会运行。

它的功能应该有点像 Google 的搜索自动建议 - 确实如此。但是,当返回一些建议时,如果用户点击键盘上的其中一个箭头,则不会选择任何建议。

这里是我的JS(对于一个建议的选择):

$(document).ready(function(){
    var $result = $('li');

    $('input').keydown(function(e){
        var key = e.keyCode, $selected = $result.filter('.selected'), $current;
        if(key != 40 && key != 38){ 
            return;
        }
        $result.removeClass('selected');
        if (key == 40){
            if (!$selected.length || $selected.is(':last-child')){
                $current = $result.eq(0);
            } else {
                $current = $selected.next();
            }
        } else if (key == 38){
            if (!$selected.length || $selected.is(':first-child')){
                $current = $result.last();
            } else {
                $current = $selected.prev();
            }
        }

        $current.addClass('selected');
    });
});

这是我的 Ajax:

function findmatch(){
    if(window.XMLHttpRequest){
        xmlhttp = new XMLHttpRequest();
    } else {
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    }

    xmlhttp.onreadystatechange = function(){
        if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
            document.getElementById('s-dif').innerHTML = xmlhttp.responseText;
        }
    }

    var qVal = document.getElementById('query-value');

    xmlhttp.open('GET', 'search/suggest.php?q=' + qVal.value, true);
    xmlhttp.send();
}

非常基本的 HTML:

<div class="form-container">
    <form method="get" id="search" name="search">
        <input type="text" name="q" id="query-value" onkeyup="findmatch();" placeholder="Search with Ajax...">
    </form>
</div>
<div class="suggestions">
    <ul id="s-dif">
    </ul>
</div>

最后,我的 PHP:

if(isset($_GET['q'])){
    $results = '';

    $query = trim($_GET['q']);  
    if(!empty($query)){
        $stmt = $conn->prepare("SELECT title, popularity FROM autosuggest WHERE keywords LIKE :query OR title LIKE :query ORDER BY popularity desc LIMIT 7");
        $query = $query . '%';
        $stmt->bindParam(':query', $query);
        $stmt->execute();

        $count = $stmt->rowCount();
        $i = 0;
        if($count > 0){
            while($row = $stmt->fetch(PDO::FETCH_OBJ)){
                $title = $row->title;
                $popularity = $row->popularity;

                $i++;

                $results .= '<li id="select-suggest" value="' . $i . '" name="' . $title . '">' . $title . '</li>';
            }   
        }
    }
}

print("$results");

我觉得好像问题出在我的“选择 jQuery”中,但是,我已确保三次检查所有内容,但我似乎找不到任何会阻止该功能工作的东西。

最佳答案

我不确定 Google 是如何工作的,但我相信您正在尝试执行类似以下脚本的操作。您应该能够将它应用到返回的下拉菜单中。它检查光标是否聚焦在输入字段中。如果是,则激活下面的 keyCode 脚本:

jsFiddle: https://jsfiddle.net/2wvs0tmd/

JavaScript:

// I am going to use an object, just for reuse
/*
** @param jQuery [object] Pass the jQuery object
** @param getMenu [object] jQuery DOM object (ul) that contains our menu
** @parm getKeyTap [int] This is the e.keyCode passed from the event
*/
var keyAction   =   function(jQuery,getMenu,getKeyTap)
    {
        // The variable is what is currently be acted on
        var isSelected;
        // This will designate first or last child
        var getChild;
        // This will be assigned the next, previous, or current child
        var thisChild;
        // We assign jQuery here
        var $           =   jQuery;
        // These are all the keys we allow to be struck
        var allowKeys   =   [38,40,13];
        // This is not used in this example, but can reset the keyCode
        var keyCode     =   false;
        /*
        ** @returns [boolean] This function returns if the key being pressed is arrow up/down
        */
        var upDown      =   function(getKeyTap)
            {
                return (getKeyTap == 38 || getKeyTap == 40);
            }
        /*
        ** @returns [boolean] This method returns boolean true/false if up/down arrow pressed
        */
        this.keyAllowed =   function()
            {
                return upDown(getKeyTap);
            }
        /*
        ** @description This method sees if pressed key is up/down arrow or return key
        ** @returns [boolean] Will return true/false
        */
        this.isAllowed  =   function()
            {
                return (allowKeys.indexOf(getKeyTap) != -1);
            }
        // This will manually set the keyCode (not required in this example)
        this.setKey =   function(keyCode)
            {
                getKeyTap   =   keyCode;
                return this;
            }
        /*
        ** @returns [object] This returns the current state of the DOM 
        */
        this.isSelected =   function()
            {
                return isSelected;
            }
        /*
        ** @description This will run an anonymous function passing the current DOM
        ** @param thisChild [ANY] I pass the current DOM selection but, you 
        **                        can pass whatever you want 
        ** @param func [function] This is what you want to run when the 
        **                        return key is pressed
        */
        this.setReturn  =   function(thisChild,func)
            {
                if(getKeyTap == 13) {
                    if(thisChild)
                        func(thisChild);
                }
            }
        /*
        ** @description This will set the current DOM and add the select class
        ** @returns This will return the current DOM object
        */
        this.firstClick =   function()
            {
                getChild    =   (getKeyTap == 38)? 'last' : 'first';
                isSelected  =   getMenu.children('li:'+getChild+'-child');
                isSelected.addClass('selected');
                return isSelected;
            }
        /*
        ** @description This method will move the selection up and down
        ** @param isSelected [object] This is the current select DOM object
        ** @returns [object] this will return the current selected DOM object
        */
        this.currClick  =   function(isSelected)
            {
                var setSpot =   'last';

                if(getKeyTap == 38)
                    thisChild   =   isSelected.prev();
                else if(getKeyTap == 40) {
                    thisChild   =   isSelected.next();
                    setSpot     =   'first';
                }

                if(!thisChild.hasClass('selectable'))
                    thisChild   =   getMenu.children("li:"+setSpot+"-child");

                isSelected.removeClass('selected');
                thisChild.addClass('selected');
                return thisChild;
            }

        /*
        ** @description This will just run a function
        */
        this.doAction   =   function(func)
            {
                return func();
            }
    }

// When document is ready
$(document).ready(function(){
    // Set container for this menu
    var isSelected  =   false;
    var qBox        =   $('input[name=q]');
    // Use the document object to listen for a key press
    $(this).keydown(function(e) {
        // See where the cursor is focused
        var isFocused   =   (e.target.nodeName == 'INPUT');
        // Start engine
        var sMenu       =   new keyAction($, $('ul'), e.keyCode);
        // If it's focused
        if(isFocused) {
            // Place text into field on return          
            sMenu.setReturn(isSelected,function(obj) {
                qBox.val(isSelected.text());
                // Submit form
                $('#search').submit();
            });

            // If keys are allowed
            if(sMenu.keyAllowed()) {
                isSelected  =   (!isSelected)? sMenu.firstClick(isSelected) : sMenu.currClick(isSelected);
                // Copy the value of the selection into the input
                sMenu.doAction(function(){
                    qBox.val(isSelected.text());
                });
            }
        }
    });
    // On key up in the text field
    qBox.on('keyup',function(e){
        // If the key pressed is up or down arrow
        if(e.keyCode == 38 || e.keyCode == 40)
            // Don't do ajax call
            return false;
        // Run ajax
        $.ajax({
            url:"search/suggest.php",
            type:"get",
            data: $(this).serialize(),
            success:function(response) {
                $('#dropdown_search').html(response);
            }
        });
    });
});

风格:

.selected {
    background-color: #888;
}

HTML:表单

<div class="form-container">
    <form id="search" name="search">
        <input type="text" name="q" id="query-value" placeholder="Search with Ajax...">
    </form>
</div>
<ul id="dropdown_search">
</ul>

HTML:从 ajax 返回(只是示例)

<li class="selectable">666554366</li>
<li class="selectable">1174971318</li>
<li class="selectable">1809433410</li>
<li class="selectable">452149182</li>
<li class="selectable">2024548770</li>

关于javascript - 自动建议下拉菜单不使用向上/向下箭头键选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38495312/

相关文章:

javascript - 将数组值从 php 复制到 javascript

php - 验证 Laravel 中的选择表单

javascript - jqGrid 中 onCellSelect 函数的完全相反是什么?

javascript - jquery:下拉菜单不显示固定位置 div 顶部的边框样式

python - 如何将 Pandas 数据框显示为数据表?

提交表单时的 JavaScript 问题

javascript - 使用javascript替换文本区域中句子中的多个单词

php - 根据当前站点显示内容

javascript - 如何阻止我的搜索功能检查大小写(大写/小写) - Javascript/ReactJS

php - 这个 MySQL 查询是 JOIN、常规查询还是两者兼而有之?