最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - UpDownLeftRight keyboard navigation with jQuery? - Stack Overflow

programmeradmin4浏览0评论

I have a list of div's all with a set and equal height/width that are float:left so they sit next to each other and fold under if that parent is smaller than the bined with of the items.

Pretty standard. This is to create a list of the twitter bootstrap icons, it gives something like this:

I have added next/previous keyboard navigation using the code below, however you will notice that the up/down arrow keys are mapped to call the left/right functions. What I have no idea how to do is to actually do the up/down navigation?

JsFiddle

(function ($) {
    $.widget("ui.iconSelect", {

        // default options
        options: {

        },

        $select: null,

        $wrapper: null,

        $list: null,

        $filter: null,

        $active: null,

        icons: {},

        keys: {
            left: 37,
            up: 38,
            right: 39,
            down: 40

        },

        //initialization function
        _create: function () {

            var that = this;
            that.$select = that.element;

            that.$wrapper = $('<div class="select-icon" tabindex="0"></div>');
            that.$filter = $('<input class="span12" tabindex="-1" placeholder="Filter by class name..."/>').appendTo(that.$wrapper);
            that.$list = $('<div class="select-icon-list"></div>').appendTo(that.$wrapper);


            //build the list of icons
            that.element.find('option').each(function () {
                var $option = $(this);
                var icon = $option.val();

                that.icons[icon] = $('<a data-class="' + icon + '"><i class="icon ' + icon + '"></i></a>');

                if ($option.is(':selected')) {
                    that.icons[icon].addClass('selected active');
                }

                that.$list.append(that.icons[icon]);
            });

            that.$wrapper.insertBefore(that.$select);
            that.$select.addClass('hide');



            that._setupArrowKeysHandler();
            that._setupClickHandler();
            that._setupFilter();
            that.focus('selected');
        },

        focus: function (type) {
            var that = this;
            if (that.$active === null || that.$active.length == 0) {
                if (type == 'first') {
                    that.$active = that.$list.find('a:visible:first');
                } else if (type == 'last') {
                    that.$active = that.$list.find('a:visible:last');
                } else if (type == 'selected') {
                    that.$active = that.$list.find('a.selected:visible:first');
                    that.focus('first');
                }
            }
            that.$active.addClass('active');
            var toScroll = ((that.$list.scrollTop() + that.$active.position().top)-that.$list.height()/2)+that.$active.height()/2;
            //that.$list.scrollTop((that.$list.scrollTop() + top)-that.$list.height()/2);
            that.$list.stop(true).animate({
                scrollTop: toScroll,
                queue: false,
                easing: 'linear'
            }, 200);

            if (type === 'selected') {
                return false;
            }

            that.$select.val(that.$active.data('class'));
            that.$select.trigger('change');

        },

        _setupArrowKeysHandler: function () {
            var that = this;

            that.$wrapper.on('keydown', function (e) {
                switch (e.which) {
                    case that.keys.left:
                        that.moveLeft();
                        break;
                    case that.keys.up:
                        that.moveUp();
                        break;
                    case that.keys.right:
                        that.moveRight();
                        break;
                    case that.keys.down:
                        that.moveDown();
                        break;
                    case 16:
                        return true;
                    case 9:
                        return true;
                    break;
                    default:
                        that.$filter.focus();
                        return true;
                }
                return false;
            });
        },

        _setupFilter: function(){
            var that = this;

            that.$filter.on('keydown keyup keypress paste cut change', function(e){
                that.filter(that.$filter.val());
            });
        },

        _setupClickHandler: function () {
            var that = this;
            that.$list.on('click', 'a', function () {
                that.$wrapper.focus();
                that.$active.removeClass('active');
                that.$active = $(this);
                that.focus('first');
            });
        },

        moveUp: function () {
            var that = this;
            return that.moveLeft();
        },

        moveDown: function () {
            var that = this;
            return that.moveRight();
        },

        moveLeft: function () {
            var that = this;
            that.$active.removeClass('active');
            that.$active = that.$active.prevAll(':visible:first');
            that.focus('last');
            return false;
        },

        moveRight: function () {
            var that = this;
            that.$active.removeClass('active');
            that.$active = that.$active.nextAll(':visible:first');
            that.focus('first');
            return false;
        },

        filter: function(word){
            var that = this;
            var regexp = new RegExp(word.toLowerCase());
            var found = false;
            $.each(that.icons, function(i, $v){
                found = regexp.test(i);
                if(found && !$v.is(':visible')){
                    $v.show();
                } else if(!found && $v.is(':visible')){
                    $v.hide();
                }
            });
        }

    });
})(jQuery);

I have a list of div's all with a set and equal height/width that are float:left so they sit next to each other and fold under if that parent is smaller than the bined with of the items.

Pretty standard. This is to create a list of the twitter bootstrap icons, it gives something like this:

I have added next/previous keyboard navigation using the code below, however you will notice that the up/down arrow keys are mapped to call the left/right functions. What I have no idea how to do is to actually do the up/down navigation?

JsFiddle

(function ($) {
    $.widget("ui.iconSelect", {

        // default options
        options: {

        },

        $select: null,

        $wrapper: null,

        $list: null,

        $filter: null,

        $active: null,

        icons: {},

        keys: {
            left: 37,
            up: 38,
            right: 39,
            down: 40

        },

        //initialization function
        _create: function () {

            var that = this;
            that.$select = that.element;

            that.$wrapper = $('<div class="select-icon" tabindex="0"></div>');
            that.$filter = $('<input class="span12" tabindex="-1" placeholder="Filter by class name..."/>').appendTo(that.$wrapper);
            that.$list = $('<div class="select-icon-list"></div>').appendTo(that.$wrapper);


            //build the list of icons
            that.element.find('option').each(function () {
                var $option = $(this);
                var icon = $option.val();

                that.icons[icon] = $('<a data-class="' + icon + '"><i class="icon ' + icon + '"></i></a>');

                if ($option.is(':selected')) {
                    that.icons[icon].addClass('selected active');
                }

                that.$list.append(that.icons[icon]);
            });

            that.$wrapper.insertBefore(that.$select);
            that.$select.addClass('hide');



            that._setupArrowKeysHandler();
            that._setupClickHandler();
            that._setupFilter();
            that.focus('selected');
        },

        focus: function (type) {
            var that = this;
            if (that.$active === null || that.$active.length == 0) {
                if (type == 'first') {
                    that.$active = that.$list.find('a:visible:first');
                } else if (type == 'last') {
                    that.$active = that.$list.find('a:visible:last');
                } else if (type == 'selected') {
                    that.$active = that.$list.find('a.selected:visible:first');
                    that.focus('first');
                }
            }
            that.$active.addClass('active');
            var toScroll = ((that.$list.scrollTop() + that.$active.position().top)-that.$list.height()/2)+that.$active.height()/2;
            //that.$list.scrollTop((that.$list.scrollTop() + top)-that.$list.height()/2);
            that.$list.stop(true).animate({
                scrollTop: toScroll,
                queue: false,
                easing: 'linear'
            }, 200);

            if (type === 'selected') {
                return false;
            }

            that.$select.val(that.$active.data('class'));
            that.$select.trigger('change');

        },

        _setupArrowKeysHandler: function () {
            var that = this;

            that.$wrapper.on('keydown', function (e) {
                switch (e.which) {
                    case that.keys.left:
                        that.moveLeft();
                        break;
                    case that.keys.up:
                        that.moveUp();
                        break;
                    case that.keys.right:
                        that.moveRight();
                        break;
                    case that.keys.down:
                        that.moveDown();
                        break;
                    case 16:
                        return true;
                    case 9:
                        return true;
                    break;
                    default:
                        that.$filter.focus();
                        return true;
                }
                return false;
            });
        },

        _setupFilter: function(){
            var that = this;

            that.$filter.on('keydown keyup keypress paste cut change', function(e){
                that.filter(that.$filter.val());
            });
        },

        _setupClickHandler: function () {
            var that = this;
            that.$list.on('click', 'a', function () {
                that.$wrapper.focus();
                that.$active.removeClass('active');
                that.$active = $(this);
                that.focus('first');
            });
        },

        moveUp: function () {
            var that = this;
            return that.moveLeft();
        },

        moveDown: function () {
            var that = this;
            return that.moveRight();
        },

        moveLeft: function () {
            var that = this;
            that.$active.removeClass('active');
            that.$active = that.$active.prevAll(':visible:first');
            that.focus('last');
            return false;
        },

        moveRight: function () {
            var that = this;
            that.$active.removeClass('active');
            that.$active = that.$active.nextAll(':visible:first');
            that.focus('first');
            return false;
        },

        filter: function(word){
            var that = this;
            var regexp = new RegExp(word.toLowerCase());
            var found = false;
            $.each(that.icons, function(i, $v){
                found = regexp.test(i);
                if(found && !$v.is(':visible')){
                    $v.show();
                } else if(!found && $v.is(':visible')){
                    $v.hide();
                }
            });
        }

    });
})(jQuery);
Share Improve this question asked Jul 1, 2013 at 12:09 HailwoodHailwood 92.8k112 gold badges273 silver badges425 bronze badges 3
  • you could call the left/right function as often as many items are in each row - would be the easiest without even taking a look at your code ;) i will do that now... – luk2302 Commented Jul 1, 2013 at 12:16
  • @luk2302, Possible solution yes, but how do you count how many items are in the row? I guess I could do $wrapper.width() mod $element.width() but the whole approach seems rather hacky to me. I've been looking into zehnet.de/2010/11/19/… but I cannot work out how to make the point relative to the wrapper... – Hailwood Commented Jul 1, 2013 at 12:19
  • what is wrong with using just the code you provided in the link. if you just paste the code and added your own, it should work: you can get the element above via $.elementFromPoint($(that.$active).offset().left, $(that.$active).offset().top-10); . For the below one you would have to add 10 + the height of one item itself, but thats fixed. I don´t know how to change the active-attribute in your code, therefore i don´t provide an answer, just a ment. – luk2302 Commented Jul 1, 2013 at 12:48
Add a ment  | 

2 Answers 2

Reset to default 2

Perhaps something like this: http://jsfiddle/QFzCY/

var blocksPerRow = 4;

$("body").on("keydown", function(e){
    var thisIndex = $(".selected").index();
    var newIndex = null;
    if(e.keyCode === 38) {
        // up
       newIndex = thisIndex - blocksPerRow;
    }
    else if(e.keyCode === 40) {
        // down
        newIndex = thisIndex + blocksPerRow;       
    }
    if(newIndex !== null) { 
        $(".test").eq(newIndex).addClass("selected").siblings().removeClass("selected");   
    }    
 });

Basically, you set how many items there are in a row and then find the current index and subtract or add that amount to select the next element via the new index.

If you need to know how many blocks per row there are, you could do this:

var offset = null;
var blocksPerRow = 0;
$(".test").each(function(){
    if(offset === null) {
        offset = $(this).offset().top;
    }
    else if($(this).offset().top !== offset) {
        return false;
    }
    blocksPerRow++;
});

To deal with your 'edge' cases, you could do:

if(newIndex >= $(".test").length) {
    newIndex = $(".test").length - newIndex;
}
    moveUp: function () {
        var that = this;
        var index = $(this).index();
        var containerWidth = parseInt( $('.select-icon-list').innerWidth(), 10);
        var iconWidth = parseInt( $('.select-icon-list > a').width(), 10);
        var noOfCols = Math.floor( containerWidth / iconWidth );
        var newIndex = ( (index - noOfCols) < 0 ) ? index : (index - noOfCols);
        var elem = $('.select-icon-list > a')[index];
    },

Cache what ever remains static.

发布评论

评论列表(0)

  1. 暂无评论