jQuery可排序列表 - 滚动条在排序时跳转

时间:2009-11-14 19:43:14

标签: jquery jquery-ui jquery-ui-sortable

我创建了一个演示:http://pastebin.me/584b9a86d715c9ba85b7bebf0375e237

当滚动条位于底部并拖动项目以对其进行排序时,会导致滚动条向上跳跃。它似乎在FF,Safari,Chrome和IE(至少IE8)中这样做。

在我的Mac上的Firefox中,当滚动条位于底部时,它会跳起来,但也会为整个列表添加一个漂亮的闪存。它只是在向上滚动整个列表时闪烁。我相信如果我弄清楚导致向上滚动的原因(如果我可以阻止它),闪烁也会停止。

我不喜欢它像那样跳起来b / c我发现它很刺耳和混乱。我知道这是一个有点角落的情况,但如果可以,我想解决它。

那么,有没有办法防止它向上滚动?或者,是什么导致它向上滚动?

由于

12 个答案:

答案 0 :(得分:46)

问题很简单。

首先让我们设置场景。您有一个可排序元素列表,您的页面高于您的屏幕,因此它有一个滚动条,您的页面位于最底部,滚动条一直向下。

问题是,你去拖动一个元素,导致jQuery从dom中删除它然后添加一个占位符。让它慢下来,它首先删除元素,现在列表更短,导致页面更短,导致滚动条更短。然后将其添加占位符,现在页面较长,现在srollbar较长(但窗口犯规向后滚动下来,所以会出现在滚动条跳起来)。

我发现抵消这种情况的最好方法是确保可排序列表具有静态高度,因此删除元素不会导致它变短。这样做的一种方法是

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

上面的内容将在创建可排序列表时调用,静态设置其高度为当前高度。

如果您在其中一个可排序元素中有图片,则除非您预先定义标记中的尺寸,否则上述代码将无效。原因是当调用和设置height()时,它在图像填写之前进行计算。没有尺寸,那么图像就没有空间。一旦图像加载,它就会占用空间。

这是一种必须定义尺寸的方法。每次检测到要加载的图像时,只需调整列表高度即可。

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

最终版本:

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;
            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);
        }
    });
});

答案 1 :(得分:20)

我在使用div容器和div元素时遇到了同样的问题,并且设置容器高度对我没有帮助,但在包含div上显式设置overflow:auto css属性确实解决了问题。仅在Chrome中测试过。

答案 2 :(得分:13)

我也遇到过这个问题。当列表指示页面的长度时会发生这种情况。当您开始排序时,列表高度会瞬间变化,从而导致页面跳转。这是一个奇怪但非常实用的解决方案:

$('ul').height($('ul').height());

答案 3 :(得分:5)

劳拉,看起来这样4年后仍然没有打补丁。这是ticket

添加到@Carl M. Gregory的答案,为了充分利用动态容器而不是将其设置在固定高度,我将编辑 jquery.ui.sortable.js 核心文件。

简单地回到第228行。this._createPlaceHolder... 第208行之前。this.helper.css("position", "absolute");

感谢jquery故障单门户网站上的 Honda 。我使用的是Sortable.js版本1.10.3。

答案 4 :(得分:5)

Carl M. Gregory完美地解释了这个问题,但我认为他的解决方案不必要地复杂化了。

将列表高度设置为固定值可以解决问题,但是在创建列表时这样做太早了。您可以使用.mousedown()功能在排序开始之前设置高度。到目前为止,任何潜在的图像都已加载,因此无需检查其大小。

所以跳转并没有发生,但现在请考虑一下:你有多个连接的列表,它们是垂直排列的。现在发生这种情况:

  1. 您开始从上方列表中拖动
  2. 上面的列表现在有固定的高度
  3. 将项目移至底部列表
  4. 底部列表很好地调整,因为它的'高度为auto
  5. 上面的列表仍然具有相同的固定高度,但它应该是一个较短的项目
  6. 所以在某些时候,你应该回归它的'高度回到auto。什么时候?在mouseup上已经太晚了(请参阅https://jsfiddle.net/937vv4tx/1/),但没关系,在跳转不再是威胁之后,您几乎可以立即返回正确的值。使用start()事件

    更新但您仍然希望在auto上将高度设置为.mouseup(),因为如果您只是点击项目并且不开始拖动,它仍会设置固定高度,因为.mousedown()已经发生。

    $('.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');
        }
    });
    

    这段代码非常适合我。

答案 5 :(得分:3)

感谢您提供出色的解决方案 但我建议使用以下代码:

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());
}

答案 6 :(得分:3)

所以,复杂!您所要做的就是将overflow: auto;添加到父级(ul,#element,whatever_you_call_it),它应该可以正常工作。这样可以确保即使文档稍微改变高度,在调整大小时,溢出自动也会保留元素的高度。

答案 7 :(得分:2)

Carl M. Gregory正在解释为什么会发生这种情况'很清楚。

然而,固定高度似乎不够,因为当您调整窗口大小时内部内容会变得更高。

我希望能做什么:

  1. 倾听排序'开始'事件,并修复可排序的高度 容器
  2. 倾听可排序'停止'事件,并将高度设置为自动(以确保在调整窗口大小时没有问题)
  3. 实践中会发生什么:在我们捕获开始事件之前发生了跳转,因此无法使用

    解决方法:监听可排序项目上的jquery mousedown和mouseup事件。这非常简单。

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

    我建议你仍然考虑卡尔关于图像加载的观点。他的回答值得一读。

答案 8 :(得分:0)

我在Chrome中遇到过这个问题。所有可排序的div都有固定的高度。

问题出在这些div的css属性position: relative中。当从DOM拖拽div时,由于相对位置,它的坐标计算错误。

Inheritabsolute定位应用于可排序元素。

答案 9 :(得分:0)

这就是我解决问题的方法。

   $(".groups").sortable({
    ...
    helper: function(event, ui){
      lastScrollPosition =  $("body").scrollTop();
    },
    start: function(e, ui){
        // avoid scroll jump
        $("body").scrollTop(lastScrollPosition);
    },
   });

答案 10 :(得分:0)

我正在将可排序的div VIA Ajax加载到具有自动高度的包装器中。

我没有尝试链接到可排序的事件,而是在加载和更改列表时将高度设置为自动,然后将其设置为静态高度。

Vit的解决方案类似,但我不想在每个mousedownmouseup事件上添加不必要的开销。相反,我只是在列表更改负载或添加新元素时执行此操作(我使用slideDown动画,并在完成时将高度设置为静态)。

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

当我重新加载数据时,其他解决方案对我不起作用,因为我只在页面加载期间对它们进行了一次排序。

我的列表/ div随着下拉列表的变化而变化,因此我可以选择不同的列表,并且我的包装器会相应调整大小而不会产生烦人的跳跃。

如果你需要添加元素或重新加载任何东西,只需将这两行代码抛出一个函数并调用该函数。

希望这有助于某人!

答案 11 :(得分:0)

这里是解决此问题的另一种简便方法。

  1. 当鼠标进入您的排序图标时,

    $("body").css("overflow-y","hidden");
    
  2. 当鼠标离开排序图标时

    $("body").css("overflow-y","scroll");