Why overflowing menu is working bad when there are

2019-07-03 23:03发布

问题:

Here is how problem looks like:

While it should look like:

Here is function used to create poping up overflowing menu:

function updateMenu(){
    var lastItemIndex = Number.POSITIVE_INFINITY;
    var lastItemText = "";
    var maxWidth = 0;
    var overflowCount=0;
    var navHeight = $('.nav').height();
    $('.nav li').each(function(i,e){
    console.log($(e).position().top);
        if($(e).position().top>=navHeight){
            if(i<lastItemIndex) lastItemIndex=i-1;
            if($(e).width()>maxWidth) maxWidth = $(e).width();
            overflowCount++;
        }
    });
    maxWidth = Math.max(maxWidth,$('.nav li:eq('+(lastItemIndex)+')').width());
    var moreHeight = (overflowCount+2)*navHeight;
    $('#moreMenu').remove();
    if(overflowCount>0){
        $('<ul id="moreMenu"/>').appendTo('body').width(maxWidth+16).height(navHeight);
        $('#moreMenu').offset($('.nav li:eq('+(lastItemIndex)+')').offset());
        $('#moreMenu').append('<li>More...</li>');
        $('.nav li:gt('+(lastItemIndex-1)+')').each(function(i,e){
            $('#moreMenu').append('<li>'+$(e).html()+'</li>');
        });
        $('#moreMenu').hover(
            function(){$(this).height(moreHeight);},
            function(){$(this).height(navHeight);});
    }
}

And here is life jsfiddle demo of this bug (I use chrome for testing).

I wonder what is wrong with my updateMenu function, why when all menu items shall be shown in a pop up menu none is actually shown (and no html pushed into pop up menu object)?

Update fire fox also shows no items for me:

回答1:

One problem is that the selector you form with "lastItemIndex", when that's zero, is invalid:

$('.nav li:gt(' + (lastItemIndex - 1) + ')') ...

When it's zero, that'll look like .nav li:gt(-1) and that's not valid (or at least it doesn't work). If you change it to:

$('.nav li:gt(' + Math.max(0, lastItemIndex - 1) + ')')

then the <li> elements are transferred to the "More" box.

As a separate note, it's probably not the best idea to do the updates in a "resize" handler directly. Browsers fire that event very rapidly, and doing all that DOM work is going to result in sluggish behavior. Instead, what you can do is have the "resize" handler start a timer for maybe 50 or 100 milliseconds, canceling any previous timer when it does so. When the user slows down the resize enough, the timer event will fire and you can do the DOM work in there.

Here is the jsfiddle updated with the selector fix (no change to the event handling).