jQuery Sortable List - scroll bar jumps up when sorting

后端 未结 13 1029
慢半拍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:19

    I have experienced this issue as well. It happens when the list dictates the length of your page. When you start sorting, the list height changes for a split second, causing the page to jump. Here is an odd, but very functional solution to this problem:

    $('ul').height($('ul').height());
    
    0 讨论(0)
  • 2020-12-24 13:21

    Lol, looks like this still isn't patched 4 years later. Here's the ticket.

    Adding onto @Carl M. Gregory's answer, to fully take advantage of a dynamic container instead of setting it on a fixed height, i would edit the jquery.ui.sortable.js core file.

    Simply move back line 228. this._createPlaceHolder... before line 208. this.helper.css("position", "absolute");

    Thanks to Honda on the jquery ticket portal. Am using Sortable.js version 1.10.3.

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

    Carl M. Gregory explains the issue perfectly, but I think his solution is unnecessarily complicated.

    Setting list height to fixed value fixes the issue, but doing so at the moment of creating the list is way too early. You can use .mousedown() function to set the height right before the sorting starts. By this time any potential images are already loaded, so there is no need in checking their sizes.

    So the jump doesn't occur, but now please consider this: You have multiple connected list and they are arranged vertically. Now this happens:

    1. You start dragging from the upper list
    2. The upper list now has fixed height
    3. Move the item to the bottom list
    4. Bottom list nicely adjusts, because its' height is auto
    5. The upper list still has the same fixed height though it should be one item shorter

    So at some point, you should return its' height back to auto. When? On mouseup is too late (see https://jsfiddle.net/937vv4tx/1/), but it's okay, you can return the correct value almost immediately after the jump is no more a threat. Using the start() event

    Update: But you still want to set height to auto on .mouseup() because if you just click on item and don't start dragging, it still sets fixed height because the .mousedown() has already happened.

    $('.sortable').mousedown(function() {
        // set fixed height to prevent scroll jump
        // when dragging from bottom
        $(this).height($(this).height());
    }).mouseup(function () {
        // set height back to auto 
        // when user just clicked on item
        $(this).height('auto');
    }).sortable({
        connectWith: '.sortable',
        placeholder: 'placeholder',
        start: function() {
            // dragging is happening
            // and scroll jump was prevented,
            // we can set it back to auto
            $(this).height('auto');
        }
    });
    

    This code works perfectly for me.

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

    Seems like jQuery UI 1.9.2 solved the issue.

    If you are unable to change the library, there's a workaround including a simple scroll bar operation. The idea is simple:

    • Keep the previous scroll position every time you scroll.
    • Set scroll back to the previous position when you start dragging your element.

    Here you go;

    var lastScrollPosition = 0; //variables defined in upper scope
    var tempScrollPosition = 0;
    
    window.onscroll = function () { // Up to you requirement you may change it to another elemnet e.g $("#YourPanel").onscroll
        clearTimeout($.data(this, 'scrollTimer'));
        $.data(this, 'scrollTimer', setTimeout(function () {
            tempScrollPosition = lastScrollPosition; // Scrolls don't change from position a to b. They cover some numbers between a and b during the change to create a smooth sliding visual. That's why we pick the previous scroll position with a timer of 250ms.
        }, 250));
    
        lastScrollPosition = $(document).scrollTop(); // Up to you requirement you may change it to another elemnet e.g $("#YourPanel").onscroll
    };
    
    $("#YourSortablePanel").sortable({
        start: function (event, ui) {
            $(document).scrollTop(tempScrollPosition);
        }
    });
    
    0 讨论(0)
  • 2020-12-24 13:24

    Thanks for the great solution but I recommend using the following instead:

    create:function(){
        var list=this;
        resize=function(){
            jQuery(list).css("min-height","0");
            jQuery(list).height(jQuery(list).height());
        };
        jQuery(list).css('min-height', jQuery(list).height());
    }
    
    0 讨论(0)
  • 2020-12-24 13:24

    This is how i solve the issue.

       $(".groups").sortable({
        ...
        helper: function(event, ui){
          lastScrollPosition =  $("body").scrollTop();
        },
        start: function(e, ui){
            // avoid scroll jump
            $("body").scrollTop(lastScrollPosition);
        },
       });
    
    0 讨论(0)
提交回复
热议问题