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

rfa*_*ams 27 jquery jquery-ui jquery-ui-sortable

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

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

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

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

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

谢谢

小智 47

问题很简单.

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

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

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

create:function(){
    jQuery(this).height(jQuery(this).height());
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

create:function(){
    var list=this;
    jQuery(list).find('img').load(function(){
        jQuery(list).height(jQuery(list).height());
    });
}
Run Code Online (Sandbox Code Playgroud)

最终版本:

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);
        }
    });
});
Run Code Online (Sandbox Code Playgroud)


pet*_*ket 22

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

  • "你是我的救世主,伙计!" 它的作用非常棒.(也适用于Firefox) (2认同)

Jon*_*han 13

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

$('ul').height($('ul').height());
Run Code Online (Sandbox Code Playgroud)


Ric*_*yce 5

大声笑,这样看起来仍然没有修补4年后.这是门票.

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

只需this._createPlaceHolder... 在第208 行之前移回第228 行.this.helper.css("position", "absolute");

感谢本田在jquery门票网站上.我使用的是Sortable.js版本1.10.3.

  • 如果有人使用其他版本,甚至是自定义的jQuery UI构建(使用不同的行号),只需查找Sortable小部件代码,并在函数_mouseStart()中移动行`this._createPlaceHolder ...`行`之前.helper.css("position","absolute");`. (2认同)

Vít*_*uer 5

卡尔·格雷格里(Carl M. Gregory)完美地解释了这个问题,但是我认为他的解决方案不必要地复杂。

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

因此不会发生跳转,但是现在请考虑以下事项:您具有多个连接列表,并且它们是垂直排列的。现在,这发生了:

  1. 您开始从上方列表中拖动
  2. 上面的列表现在具有固定的高度
  3. 将项目移到底部列表
  4. 底部列表很好地进行了调整,因为其高度为 auto
  5. 上方列表的固定高度仍然相同,尽管应该短一个

因此,在某个时候,您应该将其高度恢复为auto。什么时候?On 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');
    }
});
Run Code Online (Sandbox Code Playgroud)

这段代码非常适合我。