jQuery可排序列表 – 滚动条在排序时跳转
我创建了一个演示: http : //pastebin.me/584b9a86d715c9ba85b7bebf0375e237
当滚动条位于底部并拖动项目以对其进行排序时,会导致滚动条向上跳跃。 它似乎在FF,Safari,Chrome和IE(至少IE8)中这样做。
在我的Mac上的Firefox中,当滚动条位于底部时它会跳起来,但也会为整个列表添加一个漂亮的闪存。 它只是在向上滚动整个列表时闪烁。 我相信,如果我弄清楚是什么导致向上滚动(如果我可以阻止它),闪烁也将停止。
我不喜欢它像那样跳起来b / c我发现它很刺耳和混乱。 我知道这是一个角落的案例,但如果可以,我想解决它。
那么,有没有办法阻止它向上滚动? 或者,是什么导致它向上滚动?
谢谢
问题很简单。
首先让我们设置场景。 您有一个可排序元素列表,您的页面高于您的屏幕,因此它有一个滚动条,您的页面位于最底部,滚动条一直向下。
问题是,你去拖动一个元素,导致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); } }); });
我在使用div容器和div元素时遇到了同样的问题,设置容器高度对我没有帮助,但在包含div上显式设置overflow:auto css属性确实解决了问题。 仅在Chrome中测试过。
我也遇到过这个问题。 当列表指示页面的长度时会发生这种情况。 当您开始排序时,列表高度会瞬间变化,从而导致页面跳转。 这是一个奇怪但非常实用的解决方案:
$('ul').height($('ul').height());
大声笑,这样看起来仍然没有修补4年后。 这是票 。
添加到@Carl M. Gregory的答案,为了充分利用动态容器而不是将其设置在固定高度,我将编辑jquery.ui.sortable.js核心文件。
简单地向后移动第228行this._createPlaceHolder...
在第208行之前this.helper.css("position", "absolute");
感谢本田在jquery门票网站上。 我使用的是Sortable.js版本1.10.3。
Carl M. Gregory完美地解释了这个问题,但我认为他的解决方案不必要地复杂化。
将列表高度设置为固定值可以解决问题,但在创建列表时这样做太早了。 您可以使用.mousedown()
函数在排序开始之前设置高度。 此时任何潜在的图像都已加载,因此无需检查其大小。
所以跳转不会发生,但现在请考虑一下:你有多个连接列表,它们是垂直排列的。 现在这发生了:
- 您从上面的列表开始拖动
- 上面的列表现在有固定的高度
- 将项目移动到底部列表
- 底部列表很好地调整,因为它的高度是
auto
- 上面的列表仍然具有相同的固定高度,但它应该是一个较短的项目
所以在某些时候,你应该将它的高度恢复为auto
。 什么时候? 在mouseup
上为时已晚(请参阅https://jsfiddle.net/937vv4tx/1/ ),但没关系,在跳转不再是威胁之后,您几乎可以立即返回正确的值。 使用start()
事件
更新:但你仍然希望在.mouseup()
上设置auto
高度,因为如果你只是点击项目并且不开始拖动,它仍然设置固定高度,因为.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'); } });
这段代码非常适合我。
感谢您提供了出色的解决方案,但我建议您使用以下内容:
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()); }
Carl M. Gregory非常清楚地解释了“为什么会发生这种情况”。
然而,修复高度似乎不够,因为当您调整窗口大小时内部内容会变得更高。
我希望可以做到:
- 收听可排序的“开始”事件,并修复可排序容器的高度
- 收听可排序的“停止”事件,并将高度设置为自动(以确保在调整窗口大小时没有问题)
在实践中会发生什么:跳转发生在我们捕获开始事件之前,因此无法使用
解决方法:在可排序项上侦听jquery mousedown和mouseup事件。 这很直截了当。
$(".sortable_item").mousedown(function(){ $(".sortable_container").height($(".sortable_container").height()); }).mouseup(function(){ $(".sortable_container").height('auto'); });
我建议你仍然考虑卡尔关于图像加载的观点。 他的回答值得一读。
所以,复杂! 你所要做的就是添加overflow: auto;
到父(ul,#element,whatever_you_call_it),它应该工作。 这样可以确保即使文档稍微改变高度,在resize时,溢出自动也会保留元素的高度。
好像jQuery UI 1.9.2解决了这个问题。
如果您无法更改库,则可以使用简单的滚动条操作。 这个想法很简单:
- 每次滚动时保持上一个滚动位置。
- 开始拖动元素时,将滚动设置回上一个位置。
干得好;
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 eg $("#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 eg $("#YourPanel").onscroll }; $("#YourSortablePanel").sortable({ start: function (event, ui) { $(document).scrollTop(tempScrollPosition); } });
我在Chrome中遇到过这个问题。 所有可排序的div都有固定的高度。
问题出在css属性position: relative
这些div的position: relative
性。 当从DOM拖拽div时,由于相对位置,它的坐标计算错误。
应该对可排序元素使用Inherit
或absolute
定位。
这就是我如何解决这个问题。
$(".groups").sortable({ ... helper: function(event, ui){ lastScrollPosition = $("body").scrollTop(); }, start: function(e, ui){ // avoid scroll jump $("body").scrollTop(lastScrollPosition); }, });
我正在将我的可排序div VIA Ajax加载到具有自动高度的包装器中。
我没有尝试链接到可排序的事件,而是在加载和更改列表时将高度设置为自动,然后将其设置为静态高度。
Vit的解决方案类似,但我不想在每个mousedown
和mouseup
事件上添加不必要的开销。 相反,我只是在列表更改负载或添加新元素时执行此操作(我使用slideDown
动画,并在完成时将高度设置为静态)。
$("#wrapper").load("list.php",function() { $("#wrapper").css({ "height":"auto" }); $("#wrapper").css({ "height": $("#wrapper").height() }); }
当我重新加载数据时,其他解决方案对我不起作用,因为我只在页面加载期间对它们进行了一次排序。
我的list / div随着下拉列表的变化而变化,因此我可以选择不同的列表,并且我的包装器会相应resize而不会产生烦人的跳转。
如果你需要添加元素或重新加载任何东西,只需将这两行代码抛入一个函数并调用该函数。
希望这有助于某人!
这是解决此问题的另一个简单选择。
-
当mouseenter你的排序图标,
$("body").css("overflow-y","hidden");
-
当mouseleave你的排序图标
$("body").css("overflow-y","scroll");