jQuery Sortable List - scroll bar jumps up when sorting

后端 未结 13 1027
慢半拍i
慢半拍i 2020-12-24 12:28

I created a demo: http://pastebin.me/584b9a86d715c9ba85b7bebf0375e237

When the scroll bar is at the bottom and you drag items to sort them, it causes the scroll bar

相关标签:
13条回答
  • 2020-12-24 13:09

    Carl M. Gregory is explaining the 'why this is happening' very clearly.

    However fixing the height doesn't seem enough, since the inner content can become taller when you resize the window.

    What I wish could be done:

    1. Listen to sortable 'start' event, and fix the height of the sortable container
    2. Listen to sortable 'stop' event, and set back the height to auto (to make sure that there is no problem when resizing the window)

    What happens in practice: The jump happens before we catch the start event, so this cannot be used

    The workaround: listen to the jquery mousedown and mouseup events on the sortable items. It's very straightforward.

    $(".sortable_item").mousedown(function(){
        $(".sortable_container").height($(".sortable_container").height());
    }).mouseup(function(){
        $(".sortable_container").height('auto');
    });
    

    I suggest you still consider Carl's point about images loading. His answer is worth a read.

    0 讨论(0)
  • 2020-12-24 13:12

    I had the same issue when using a div container and div elements and setting the container height didn't help me, but explicitly setting overflow:auto css property on the containing div did fix the issue. Only tested in Chrome though.

    0 讨论(0)
  • 2020-12-24 13:13

    I had this issue in Chrome. And all sortable divs had fixed height.

    Problem was in css property position: relative of these divs. When div was dragged and removed from DOM, it's coordinates were calculated wrong due to relative position.

    Inherit or absolute positioning should be used for sortable elements.

    0 讨论(0)
  • 2020-12-24 13:14

    The problem is very simple.

    First let's set up the scenario. You have a list of sortable elements, your page is higher than your screen so it has a scrollbar, your page is at the very bottom, the scroll bar all the way down.

    The issue, you go to drag an element which causes jQuery to remove it from the dom then add in a placeholder. Let’s slow it down, it removes the element first, now the list is shorter causing the page to be shorter, causing the scrollbar to be shorter. Then it adds the placeholder, now the page is longer, now the srollbar is longer (but the window doesnt scroll back down, so it appears the scroll bar jumped up).

    Best way I found to counteract this would be to ensure the sortable list has a static height, so removing an element doesn't cause it to go shorter. One method of doing this would be

    create:function(){
        jQuery(this).height(jQuery(this).height());
    }
    

    The above will be called upon the creation of the sortable list, staticly setting its height to it's current height.

    If you have pictures in one of the sortable elements, the above code will not work unless you pre-define the dimensions in the tag. Reason is that when the height() is called and set, it's calculating before the image is filled out. No dimension, then the image accounts for no space. Once the image loads, then will it take up space.

    Here is a way around having to define dimensions. Simply resize the list height every time an image within is detected to be loaded.

    create:function(){
        var list=this;
        jQuery(list).find('img').load(function(){
            jQuery(list).height(jQuery(list).height());
        });
    }
    

    Final version:

    jQuery(document).ready(function(){  
        jQuery("div#todoList").sortable({
            handle:'img.moveHandle',
            opacity: 0.6,
            cursor: 'move',
            tolerance: 'pointer',
            forcePlaceholderSize: true,
            update:function(){
                jQuery("body").css('cursor','progress');
                var order = jQuery(this).sortable('serialize');
                jQuery.post("/ajax.php?do=sort&"+order,function(data){jQuery("body").css('cursor','default');});
            },
            create:function(){
                var list=this;
                var resize=function(){
                    jQuery(list).css("height","auto");
                    jQuery(list).height(jQuery(list).height());
                };
                jQuery(list).height(jQuery(list).height());
                jQuery(list).find('img').load(resize).error(resize);
            }
        });
    });
    
    0 讨论(0)
  • 2020-12-24 13:15

    So, complex! All you have to do is add overflow: auto; to the parent (ul, #element, whatever_you_call_it), and it should work. This ensures that even if the document changes height slightly, that when resizing, the overflow auto will retain the element's height.

    0 讨论(0)
  • 2020-12-24 13:18

    I was loading my sortable divs VIA Ajax into a wrapper with an auto height.

    Instead of trying to link into sortable events, I just made the height auto when loading and changing the list and then set it to a static height afterwards.

    Vit's solution is similar, but I didn't want to add unnecessary overhead by doing this on every mousedown and mouseup event. Instead, I just do it when the list is changing on the load or when new elements are added (I use a slideDown animation and just set the height to static when it is complete).

    $("#wrapper").load("list.php",function() {
        $("#wrapper").css({ "height":"auto" });
        $("#wrapper").css({ "height": $("#wrapper").height() });
    }
    

    The other solutions weren't working for me when I reload data as I only made them sortable once during the page load.

    My list/div changes with a dropdown so I am able to select different lists and my wrapper resizes accordingly without the annoying jump.

    If you need to add elements or reload anything, just throw those two lines of code into a function and call the function.

    Hope this helps someone!

    0 讨论(0)
提交回复
热议问题