专注于搜索文本字段并使搜索列表可导航

时间:2012-10-26 14:58:13

标签: javascript javascript-events user-interface google-chrome-extension unobtrusive-javascript

我在其中一个代码中有一个搜索功能,理想情况下会对值列表(小数字)执行搜索。

<li>abc</li> 
<li>def</li> 
...

我在底部有一个搜索按钮,我放了一个keyup事件监听器来获取即时搜索。现在的问题是如何让它可以导航。 理想的场景搜索一些文本,点击回车,它应该打开第一个元素,否则你应该能够浏览。

如果我上面不清楚,我实际上要求的功能与FB聊天侧边栏搜索非常相似。

4 个答案:

答案 0 :(得分:1)

为了没有将jQuery添加到标签列表的OP(我祝贺你),我将在纯JavaScript中添加一个小的导航插件。

披露 - 实际逻辑的功劳将归功于Facebook的名人Eric Priestley,因为这是从他的Javelin JS库中取消的。

我发布了一个指向小提琴here的链接。我还从您的问题中假设您已经有一个搜索解决方案,并且只是在寻找导航解决方案。

小提琴交叉发布。我在代码中评论了很多,所以应该自我解释。虽然如果你有疑虑,请联系。

<强> HTML 可以是你想要的任何东西。为简洁起见,我添加了这个

<input id='control' type='text' placeholder='Search text here' />
<!-- List of results - hardcoded for now -->
<ul id='hardpoint' class='hidden'>
    <li class='item'>Search item 1</li>
    <li class='item'>Search item 2</li>
    <li class='item'>Search item 3</li>
    <li class='item'>Search item 4</li>
</ul>​

代码

(function() {


    /**
     * Helper functions
     */
    var bind = function( context, func, more ){
        if (typeof func !== 'function') {
            throw new Error ("No function supplied to bind function");
        }
        var bound = Array.prototype.slice.call( arguments ).slice(2);
        if (func.bind) {
            return func.bind.apply(func, [context].concat(bound));
        }
        return function() {
            return func.apply(context || window, bound.concat(Array.prototype.slice.call( arguments )));
        }
    };

    var getChildElements = function(node) {
        var childNodes = Array.prototype.slice.call(node.childNodes);
        childNodes = childNodes.filter(function(item) {
            return item.tagName && item.nodeType && item.nodeType === 1 && item !== node;
        });
        return childNodes;
    };

    var hasClass = function(node, className) {
        return ((' ' + node.className + ' ').indexOf(' ' + className + ' ') > -1);
    };

    var alterClass = function(node, className, add) {
        var has = hasClass(node, className);
        if (add && !has) {
            node.className = node.className.trim() + ' ' + className;
        }
        else if (has && !add) {
            node.className = node.className.replace(
            new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), ' ');
        }
    };

    var getIndex = function( list, element ){
        var index = -1;
        for (var i = 0; i < list.length; i++) {
            if( list[i] === element ){
                index = i;
                break;
            }
        };
        return index;
    };


    // Start of plugin
    // Constructor
    var ListNavigator = function(config) {};

    // This can be moved within constructor if you so prefer
    ListNavigator.prototype.init = function(config) {
        // On what element do you want the controls to activate
        // Pressing up down etc on this element, triggers tha navigation
        this.control = document.getElementById(config.control);

        // The list of results that can be navigated
        this.hardpoint = document.getElementById(config.hardpoint);

        // A list of items ( usually, childNodes ) of hardpoint
        // Dynamically populated
        this.display =  getChildElements(this.hardpoint);;

        // What to set the focus on initially
        this.focus = -1;

        // Specify a function to execute when the user chooses a result
        // Keydown - Return : configured to be the choose event type now
        this.choose = config.choose;

        this.selector = config.selector;
    };

    ListNavigator.prototype.run = function() {
        var controlEvents = ['focus', 'blur', 'keydown', 'input'],
            mouseEvents = [ 'mouseover', 'mouseout', 'mousedown' ],
            self = this,
            selector = this.selector;

        controlEvents.forEach(function(event) {
            self.control.addEventListener(event, bind(self, self.handleEvent), false);
        });

        mouseEvents.forEach(function(event) {
            self.hardpoint.addEventListener(event, bind(self, self.onmouse), true);
        });
    };

    // Logic to change the focus on keydown
    ListNavigator.prototype.changeFocus = function(d) {
        var n = Math.min( Math.max( -1, this.focus + d ), this.display.length - 1);

        if (this.focus >= 0 && this.focus < this.display.length) {
            alterClass(this.display[this.focus], 'focused', false);
        }

        this.focus = n;
        this.drawFocus();
        return true;
    };

    // Set the focus on the targetted element
    ListNavigator.prototype.drawFocus = function() {
        var f = this.display[this.focus];
        if (f) {
            alterClass(f, 'focused', true);
        }
    };

    // Handle mouse events
    ListNavigator.prototype.onmouse = function(event) {
        var target = event.target, type = event.type;
        if ( hasClass( target, this.selector ) ) {
            if ( type === 'mousedown' ) {
                // Choose this element
                this.choose(target);
            }
            else if ( type === 'mouseover' ) {
                // Set the focus to element on which mouse is hovering on
                this.focus = getIndex( this.display, target );
                this.drawFocus();
            } 
            else if ( type === 'mouseout' ){
                // Reset the display to none
                this.changeFocus(Number.NEGATIVE_INFINITY);
            }
        };
    };

    ListNavigator.prototype.handleEvent = function(e) {
        var type = e.type;
        if (type === 'blur') {
            this.focused = false;
            this.hide();
        } else {
            alterClass(this.hardpoint, 'hidden', false);
            this.update(e);
        }
    };

    ListNavigator.prototype.hide = function() {
        this.changeFocus(Number.NEGATIVE_INFINITY);
        this.display = [];
        alterClass(this.hardpoint, 'hidden', true);
    };

    ListNavigator.prototype.submit = function() {
        if (this.focus >= 0 && this.display[this.focus]) {
            this.choose(this.display[this.focus]);
        } else {

            if (this.display.length) {
                this.changeFocus(1);
                this.choose(this.display[this.focus]);
            }
        }
        return false;
    };

    ListNavigator.prototype.update = function(event) {

        console.log( 'upadte' );
        this.display = getChildElements(this.hardpoint);

        if (event.type === 'focus') {
            this.focused = true;
        }

        var k = event.which;
        if (k && event.type == 'keydown') {
            switch (k) {
            case 38:
                if (this.display.length && this.changeFocus(-1)) {
                    event.stopPropagation();
                }
                break;
            case 40:
                if (this.display.length && this.changeFocus(1)) {
                    event.stopPropagation();
                }
                break;
            case 13:
                if (this.display.length) {
                    this.hide();
                    event.stopPropagation();
                    this.submit();
                }
                break;
            case 27:
                if (this.display.length) {
                    this.hide();
                    event.stopPropagation();
                }
                break;
            case 9:
                // If the user tabs out of the field, don't refresh.
                return;
            }
        }

    };

    window.ListNav = ListNavigator

})();

var nav = new ListNav();
nav.init({
    control: 'control',
    hardpoint: 'hardpoint',
    selector: 'item',
    choose: function(){
        console.log( arguments );
    }
});
nav.run();​

答案 1 :(得分:0)

如果这是我的页面,我会将可搜索的元素标记为<li class="searchable">abc</li>等类,我会使用jQuery通过选择器(例如$("li.searchable:contains('" + SEARCHTERM + "')"))查找页面中的所有可搜索元素我们定义了var SEARCHTERM = $(“#searchbox”)。text();

您可能想要对此进行一些微调(例如:contains包含区分大小写),但这听起来是否正确?

答案 2 :(得分:0)

您是否正在寻找自动完成功能......?如果是这样,您应该查看jQuery UI自动完成:http://jqueryui.com/autocomplete/

答案 3 :(得分:0)

<html lang="html">
<head>
<meta charset="utf-8" />
<title>Search Users</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
    $("#searched_users_list").hide();
    $("#search_user").keyup(function(){
        var what_to_search = $(this).val().toLowerCase();
        if(what_to_search != ''){
            $("#users_list").hide();
            $("#searched_users_list").show();
        }else{
            $("#users_list").show();
            $("#searched_users_list").hide();
        }
        var searched_users = '';
        var user_name = '';
        $("#users_list").children('li:contains("'+what_to_search+'")').each(function(){
            user_name = $(this).html();
            searched_users += "<li>"+user_name+"</li>";
        });

        if(searched_users != '')
            $("#searched_users_list").html(searched_users);
        else
            $("#searched_users_list").html('<li>No user found....</li>');
    })
});
</script>
</head>
<body>
<ul id="users_list">
    <li>abc</li>
    <li>defa</li>
    <li>ghife</li>
</ul>
<ul id="searched_users_list">
    <li>No user found....</li>
</ul>
<input type="text" name="search_users" id="search_user" value="" />
</body>
</html>

It's my first post... Sorry If something is odd.