jQuery Sortable List - 排序时滚动条向上跳
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1735372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jQuery Sortable List - scroll bar jumps up when sorting
提问by rfadams
I created a demo: http://pastebin.me/584b9a86d715c9ba85b7bebf0375e237
我创建了一个演示:http: //pastebin.me/584b9a86d715c9ba85b7bebf0375e237
When the scroll bar is at the bottom and you drag items to sort them, it causes the scroll bar to jump up. It seems to do this in FF, Safari, Chrome, and IE (at least IE8).
当滚动条在底部并且您拖动项目对其进行排序时,它会导致滚动条向上跳跃。它似乎在 FF、Safari、Chrome 和 IE(至少 IE8)中执行此操作。
In Firefox on my Mac, it does the jump up when the scroll bar is at the bottom, but also adds a nice flash to the whole list. It just flashes the whole list right as it scrolls it up. I believe that if I figure out what is causing the scroll up (and if I can stop it), the flashing will stop as well.
在我的 Mac 上的 Firefox 中,当滚动条位于底部时,它会向上跳转,但也会为整个列表添加一个漂亮的闪光。它只是在向上滚动时闪烁整个列表。我相信,如果我弄清楚是什么导致向上滚动(如果我能阻止它),闪烁也会停止。
I don't like it jumping up like that b/c I find it jarring and confusing. I know this is a bit of a corner case, but I'd like to fix it if I could.
我不喜欢它像 b/c 那样跳起来,我觉得它很刺耳和令人困惑。我知道这有点极端,但如果可以,我想修复它。
So, is there any way to prevent it from scrolling up? Alternately, what is causing it to scroll up?
那么,有什么办法可以防止它向上滚动吗?或者,是什么导致它向上滚动?
Thanks
谢谢
回答by Carl M. Gregory
The problem is very simple.
问题很简单。
First let's set up the scenario. You have a list of sortable elements, your page is higher than your screen so it has a scrollbar, your page is at the very bottom, the scroll bar all the way down.
首先让我们设置场景。你有一个可排序元素的列表,你的页面高于你的屏幕,所以它有一个滚动条,你的页面在最底部,滚动条一直向下。
The issue, you go to drag an element which causes jQuery to remove it from the dom then add in a placeholder. Let's slow it down, it removes the element first, now the list is shorter causing the page to be shorter, causing the scrollbar to be shorter. Then it adds the placeholder, now the page is longer, now the srollbar is longer (but the window doesnt scroll back down, so it appears the scroll bar jumped up).
问题是,您要拖动一个元素,导致 jQuery 将其从 dom 中删除,然后添加占位符。让我们放慢速度,它首先删除元素,现在列表更短导致页面更短,导致滚动条更短。然后它添加占位符,现在页面更长,现在滚动条更长(但窗口没有向下滚动,所以滚动条看起来跳起来了)。
Best way I found to counteract this would be to ensure the sortable list has a static height, so removing an element doesn't cause it to go shorter. One method of doing this would be
我发现抵消这种情况的最佳方法是确保可排序列表具有静态高度,因此删除元素不会导致它变短。这样做的一种方法是
create:function(){
jQuery(this).height(jQuery(this).height());
}
The above will be called upon the creation of the sortable list, staticly setting its height to it's current height.
上面将在创建可排序列表时调用,将其高度静态设置为当前高度。
If you have pictures in one of the sortable elements, the above code will not work unless you pre-define the dimensions in the tag. Reason is that when the height() is called and set, it's calculating before the image is filled out. No dimension, then the image accounts for no space. Once the image loads, then will it take up space.
如果您在可排序元素之一中有图片,则除非您在标签中预定义尺寸,否则上述代码将不起作用。原因是当调用并设置 height() 时,它会在填充图像之前进行计算。没有维度,则图像不占空间。一旦图像加载,那么它会占用空间。
Here is a way around having to define dimensions. Simply resize the list height every time an image within is detected to be loaded.
这是一种必须定义尺寸的方法。每次检测到要加载其中的图像时,只需调整列表高度即可。
create:function(){
var list=this;
jQuery(list).find('img').load(function(){
jQuery(list).height(jQuery(list).height());
});
}
Final version:
最终版本:
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);
}
});
});
回答by petrocket
I had the same issue when using a div container and div elements and setting the container height didn't help me, but explicitly setting overflow:auto css property on the containing div did fix the issue. Only tested in Chrome though.
我在使用 div 容器和 div 元素时遇到了同样的问题,并且设置容器高度对我没有帮助,但是在包含 div 上明确设置 overflow:auto css 属性确实解决了这个问题。不过只在 Chrome 中测试过。
回答by Jonathan
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());
回答by Vít Rotbauer
Carl M. Gregory explains the issue perfectly, but I think his solution is unnecessarily complicated.
Carl M. Gregory 完美地解释了这个问题,但我认为他的解决方案过于复杂。
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.
将列表高度设置为固定值可解决此问题,但在创建列表时这样做还为时过早。您可以使用.mousedown()
函数在排序开始之前设置高度。此时任何可能的图像都已加载,因此无需检查它们的大小。
So the jump doesn't occur, but now please consider this: You have multiple connectedlist and they are arranged vertically. Now this happens:
所以跳转不会发生,但现在请考虑这一点:您有多个连接列表,它们是垂直排列的。现在发生这种情况:
- You start dragging from the upper list
- The upper list now has fixed height
- Move the item to the bottom list
- Bottom list nicely adjusts, because its' height is
auto
- The upper list still has the same fixed height though it should be one item shorter
- 你开始从上面的列表中拖动
- 上面的列表现在有固定的高度
- 将项目移至底部列表
- 底部列表很好地调整,因为它的高度是
auto
- 上面的列表仍然具有相同的固定高度,尽管它应该短一个项目
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
因此,在某些时候,您应该将其高度返回到auto
. 什么时候?Onmouseup
为时已晚(参见https://jsfiddle.net/937vv4tx/1/),但没关系,您几乎可以在跳转不再构成威胁后立即返回正确的值。使用start()
事件
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.
更新:但您仍然希望将高度设置为auto
on.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');
}
});
This code works perfectly for me.
这段代码非常适合我。
回答by Ricky Boyce
Lol, looks like this still isn't patched 4 years later. Here's the ticket.
大声笑,看起来这在 4 年后仍然没有修补。这是票。
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.jscore file.
添加到@Carl M. Gregory 的回答中,为了充分利用动态容器而不是将其设置在固定高度,我将编辑jquery.ui.sortable.js核心文件。
Simply move back line 228. this._createPlaceHolder...
before line 208. this.helper.css("position", "absolute");
只需将第 228this._createPlaceHolder...
行移回第 208行之前。this.helper.css("position", "absolute");
Thanks to Hondaon the jquery ticket portal. Am using Sortable.js version 1.10.3.
感谢jquery 票务门户网站上的Honda。我正在使用 Sortable.js 版本 1.10.3。
回答by Avi Malka
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());
}
回答by Webmaster G
So, complex! All you have to do is add overflow: auto;
to the parent (ul, #element, whatever_you_call_it), and it should work. This ensures that even if the document changes height slightly, that when resizing, the overflow auto will retain the element's height.
所以,复杂!你所要做的就是添加overflow: auto;
到父级(ul、#element、whatever_you_call_it),它应该可以工作。这确保即使文档稍微改变高度,在调整大小时,溢出自动将保留元素的高度。
回答by RaphKomjat
Carl M. Gregory is explaining the 'why this is happening' very clearly.
Carl M. Gregory 非常清楚地解释了“为什么会发生这种情况”。
However fixing the height doesn't seem enough, since the inner content can become taller when you resize the window.
然而,固定高度似乎还不够,因为当您调整窗口大小时,内部内容可能会变得更高。
What I wish could be done:
我希望可以做到的:
- Listen to sortable 'start' event, and fix the height of the sortable container
- Listen to sortable 'stop' event, and set back the height to auto (to make sure that there is no problem when resizing the window)
- 监听可排序的 'start' 事件,并修复可排序容器的高度
- 侦听 sortable 'stop' 事件,将高度设置回 auto(以确保调整窗口大小时没有问题)
What happens in practice:The jump happens before we catch the start event, so this cannot be used
实践中会发生什么:跳转发生在我们捕获开始事件之前,所以不能使用
The workaround:listen to the jquery mousedown and mouseup events on the sortable items. It's very straightforward.
解决方法:侦听可排序项目上的 jquery mousedown 和 mouseup 事件。这非常简单。
$(".sortable_item").mousedown(function(){
$(".sortable_container").height($(".sortable_container").height());
}).mouseup(function(){
$(".sortable_container").height('auto');
});
I suggest you still consider Carl's point about images loading. His answer is worth a read.
我建议你仍然考虑卡尔关于图像加载的观点。他的回答值得一读。
回答by Barry Guvenkaya
Seems like jQuery UI 1.9.2 solved the issue.
似乎 jQuery UI 1.9.2 解决了这个问题。
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);
}
});
回答by user1274820
I was loading my sortable divs VIA Ajax into a wrapper with an auto height.
我正在通过 Ajax 将可排序的 div 加载到具有自动高度的包装器中。
Instead of trying to link into sortable events, I just made the height auto when loading and changing the list and then set it to a static height afterwards.
我没有尝试链接到可排序的事件,而是在加载和更改列表时自动设置高度,然后将其设置为静态高度。
Vit's solution is similar, but I didn't want to add unnecessary overhead by doing this on every mousedown
and mouseup
event. Instead, I just do it when the list is changing on the load or when new elements are added (I use a slideDown
animation and just set the height to static when it is complete).
维生素的解决方案是相似的,但我并不想在每次这样做是为了增加不必要的开销mousedown
和mouseup
事件。相反,我只是在加载列表更改或添加新元素时执行此操作(我使用slideDown
动画并在完成时将高度设置为静态)。
$("#wrapper").load("list.php",function() {
$("#wrapper").css({ "height":"auto" });
$("#wrapper").css({ "height": $("#wrapper").height() });
}
The other solutions weren't working for me when I reload data as I only made them sortable once during the page load.
当我重新加载数据时,其他解决方案对我不起作用,因为我只在页面加载期间将它们排序一次。
My list/div changes with a dropdown so I am able to select different lists and my wrapper resizes accordingly without the annoying jump.
我的列表/div 随下拉列表而变化,因此我可以选择不同的列表,并且我的包装器会相应地调整大小,而不会出现烦人的跳转。
If you need to add elements or reload anything, just throw those two lines of code into a function and call the function.
如果您需要添加元素或重新加载任何内容,只需将这两行代码放入一个函数并调用该函数即可。
Hope this helps someone!
希望这可以帮助某人!