jQuery Sortable List - 排序时滚动条跳起来
Posted
技术标签:
【中文标题】jQuery Sortable List - 排序时滚动条跳起来【英文标题】:jQuery Sortable List - scroll bar jumps up when sorting 【发布时间】:2010-12-16 15:53:25 【问题描述】:我创建了一个演示:http://pastebin.me/584b9a86d715c9ba85b7bebf0375e237
当滚动条位于底部并且您拖动项目以对其进行排序时,它会导致滚动条向上跳动。它似乎在 FF、Safari、Chrome 和 IE(至少 IE8)中执行此操作。
在我 Mac 上的 Firefox 中,当滚动条位于底部时它会向上跳,但也会在整个列表中添加一个漂亮的 Flash。它只是在向上滚动时闪烁整个列表。我相信,如果我找出导致向上滚动的原因(如果我能阻止它),闪烁也会停止。
我不喜欢它像 b/c 那样跳起来,我觉得它很刺耳和令人困惑。我知道这有点极端,但如果可以的话,我想解决它。
那么,有什么办法可以防止它向上滚动吗?或者,是什么导致它向上滚动?
谢谢
【问题讨论】:
我在 FF 3.6 中,我没有看到任何真正的问题。如果我抓住底部的并将其向上拖动,则该框不会滚动,直到它到达顶部。 在弄乱javascript之前尝试this solution 【参考方案1】:问题很简单。
首先让我们设置场景。您有一个可排序元素列表,您的页面高于屏幕,因此它有一个滚动条,您的页面位于最底部,滚动条一直向下。
问题,你去拖动一个元素,这会导致 jQuery 从 dom 中删除它,然后添加一个占位符。让我们放慢速度,它首先删除元素,现在列表更短导致页面更短,导致滚动条更短。然后它添加了占位符,现在页面更长了,现在滚动条更长了(但窗口不会向下滚动,所以看起来滚动条向上跳了)。
我发现解决此问题的最佳方法是确保可排序列表具有静态高度,因此删除元素不会导致它变短。这样做的一种方法是
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;
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);
);
);
【讨论】:
这段代码也解决了我的问题。谢谢你。但是这个修复还有另一个问题。如果可排序列表具有删除行选项。从列表中删除单行后,由于列表的高度是固定的,因此会留下空间。 还有一个问题。如果可排序列表不可见,则无法修复此问题。例如:可排序列表位于非活动选项卡中。 这里也一样,确保在调整窗口大小时也调整大小,尤其是对于响应式网站。因为内容高度可能会改变。但是 +1 用于处理图像案例。 我写了一个补充答案来处理窗口调整大小的情况。 老大.. 你让我开心!!非常感谢【参考方案2】:这是解决此问题的另一个简单方法。
当鼠标进入你的排序图标时,
$("body").css("overflow-y","hidden");
当鼠标离开你的排序图标时
$("body").css("overflow-y","scroll");
【讨论】:
如果你发现切换 overflow-y 会影响你的容器宽度,试试 ::-webkit-scrollbar width: 0px; 【参考方案3】:所以,复杂!您所要做的就是将overflow: auto;
添加到父级(ul,#element,whatever_you_call_it),它应该可以工作。这样可以确保即使文档的高度略有变化,在调整大小时,溢出自动将保留元素的高度。
【讨论】:
这个问题我找了很久,你的回答解决了我的问题,谢谢【参考方案4】:我正在通过 Ajax 将可排序的 div 加载到具有自动高度的包装器中。
我没有尝试链接到可排序的事件,而是在加载和更改列表时将高度设为自动,然后将其设置为静态高度。
Vit 的解决方案类似,但我不想通过在每个 mousedown
和 mouseup
事件上执行此操作来增加不必要的开销。相反,我只是在加载时列表发生变化或添加新元素时执行此操作(我使用slideDown
动画并在完成时将高度设置为静态)。
$("#wrapper").load("list.php",function()
$("#wrapper").css( "height":"auto" );
$("#wrapper").css( "height": $("#wrapper").height() );
当我重新加载数据时,其他解决方案对我不起作用,因为我只在页面加载期间使它们可排序一次。
我的列表/div 会随着下拉列表而变化,因此我可以选择不同的列表,并且我的包装器会相应地调整大小,而不会出现烦人的跳转。
如果您需要添加元素或重新加载任何内容,只需将这两行代码放入一个函数并调用该函数即可。
希望这对某人有所帮助!
【讨论】:
【参考方案5】:Carl M. Gregory 完美地解释了这个问题,但我认为他的解决方案过于复杂。
将列表高度设置为固定值可以解决问题,但在创建列表时这样做还为时过早。您可以使用.mousedown()
函数在排序开始之前设置高度。此时任何可能的图像都已加载,因此无需检查它们的大小。
所以跳转不会发生,但现在请考虑一下:您有多个已连接列表,它们是垂直排列的。现在发生了这种情况:
-
您从上方列表开始拖动
上方列表现在具有固定高度
将项目移至底部列表
底部列表调整得很好,因为它的高度是
auto
虽然上面的列表仍然具有相同的固定高度它应该短一个项目
所以在某些时候,您应该将其高度返回到auto
。什么时候?在mouseup
上为时已晚(请参阅https://jsfiddle.net/937vv4tx/1/),但没关系,您几乎可以在跳跃不再构成威胁后立即返回正确的值。使用start()
事件
更新: 但是您仍然希望在 .mouseup()
上将高度设置为 auto
,因为如果您只是单击项目而不开始拖动,它仍然会设置固定高度,因为 @987654329 @已经发生了。
$('.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');
);
这段代码非常适合我。
【讨论】:
【参考方案6】:Carl M. Gregory 非常清楚地解释了“为什么会这样”。
但固定高度似乎还不够,因为当您调整窗口大小时,内部内容可能会变得更高。
我希望能做到的事:
-
监听可排序的“开始”事件,并固定可排序的高度
容器
监听可排序的“停止”事件,并将高度设置回自动(以确保调整窗口大小时没有问题)
实际发生的情况:跳转发生在我们捕捉到开始事件之前,所以不能使用这个
解决方法: 监听可排序项目上的 jquery mousedown 和 mouseup 事件。这很简单。
$(".sortable_item").mousedown(function()
$(".sortable_container").height($(".sortable_container").height());
).mouseup(function()
$(".sortable_container").height('auto');
);
我建议您仍然考虑 Carl 关于图像加载的观点。他的回答值得一读。
【讨论】:
【参考方案7】:似乎 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 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);
);
【讨论】:
这感觉有点像 hack,因为我必须设置一个半全局变量,但这是在这个线程上唯一对我有用的东西。我正在使用隐藏内容的横向滚动 div,因此大多数其他解决方案不适用于我。我也在使用 rails-ui gem,所以我无法编辑核心文件。谢谢! 我和你有过类似的情况,想出了这个主意。我记得几天来没有任何运气的情况下查看了大量的解决方案。我很高兴这节省了其他人的时间。【参考方案8】:这就是我解决问题的方法。
$(".groups").sortable(
...
helper: function(event, ui)
lastScrollPosition = $("body").scrollTop();
,
start: function(e, ui)
// avoid scroll jump
$("body").scrollTop(lastScrollPosition);
,
);
【讨论】:
【参考方案9】:大声笑,看起来这个在 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。
【讨论】:
如果有人使用其他版本,甚至是自定义的 jQuery UI 构建(具有不同的行号),只需查找 Sortable 小部件代码并在函数 _mouseStart() 中将行this._createPlaceHolder...
移到前面线this.helper.css("position", "absolute");
.
嗯……虽然没有以前那么高了,但仍然有一个小的跳跃。【参考方案10】:
我在 Chrome 中遇到了这个问题。所有可排序的 div 都有固定的高度。
问题出在这些 div 的 css 属性 position: relative
中。 div从DOM中拖拽移除时,由于相对位置,坐标计算错误。
Inherit
或 absolute
定位应该用于可排序元素。
【讨论】:
【参考方案11】:我在使用 div 容器和 div 元素时遇到了同样的问题,并且设置容器高度对我没有帮助,但是在包含的 div 上显式设置 overflow:auto css 属性确实解决了这个问题。不过只在 Chrome 中测试过。
【讨论】:
“你是我的救星,伙计!”它工作得很好。 (也适用于 Firefox) 我添加“溢出:自动;”到我的“ol”容器中,它可以工作。谢谢!! 接受的答案对我不起作用,但确实如此。谢谢。 (是的,2019 年还在使用 jQuery UI)【参考方案12】:感谢您的出色解决方案 但我建议改用以下内容:
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());
【讨论】:
对于 cmets 来说有点晚了,但我也更喜欢这种方法……尤其是当您动态添加可排序元素时。 +1 这是什么?根本不使用resize【参考方案13】:我也遇到过这个问题。当列表指示页面的长度时,就会发生这种情况。当您开始排序时,列表高度会在一瞬间发生变化,从而导致页面跳转。这是一个奇怪但非常实用的解决方案:
$('ul').height($('ul').height());
【讨论】:
同意。问题发生的原因解释清楚,修复工作完美,快速简单。 @Matt 页面结束,当文档为ready。 这是一个不错的解决方案,但请记住,调整窗口大小时,您的“ul”内部内容可能会变高。在这种情况下,您可能需要监听窗口“调整大小”事件并相应地设置“ul”高度。以上是关于jQuery Sortable List - 排序时滚动条跳起来的主要内容,如果未能解决你的问题,请参考以下文章
Jquery-ui Sortable with js list maker from array 无法正常工作
jQuery Draggable + Sortable - 如何拒绝放入排序?