javascript - How to use jQuery UI Sortable to intersect properly?
问题描述
Here's my attempt at animating jQuery UI Sortable:
https://codepen.io/anon/pen/YdMOXE
var startIndex, changeIndex, uiHeight;
$('ul').sortable({
'placeholder': 'marker',
start: function(e, ui) {
startIndex = ui.placeholder.index();
uiHeight = ui.item.outerHeight(true);//get offset incl margin
ui.item.nextAll('li:not(.marker)').css({
transform: 'translateY(' +uiHeight+ 'px)'
});
ui.placeholder.css({
height: 0,
padding: 0
});
},
change: function(e, ui) {
changeIndex = ui.placeholder.index();
if (startIndex > changeIndex) {
var slice = $('ul li').slice(changeIndex, $('ul li').length);
slice.not('.ui-sortable-helper').each(function() {
var item = $(this);
item.css({
background:'lightcoral',
transform: 'translateY(' +uiHeight+ 'px)'
});
});
} else if (startIndex < changeIndex) {
var slice = $('ul li').slice(startIndex, changeIndex);
slice.not('.ui-sortable-helper').each(function() {
var item = $(this);
item.css({
background: 'lightgreen',
transform: 'translateY(0px)'
});
});
}
startIndex = changeIndex
},
stop: function(e, ui) {
$('.ui-sortable-handle').css({
background: 'lightblue',
transform: 'translateY(0)'
})
}
});
Unfortunately it does not work reliably with tolerance: intersect
. (sorting to change when 50%
of the element is overlapping). It seems to want to sort only via pointer location. Attached is a video to show this. https://gfycat.com/WatchfulPresentHedgehog
How do I get this to work correctly with intersect?
解决方案
You can see the bug #8342
Sortable: Incorrect behaviour (or incorrect documentation) of sortable option
tolerance: 'intersect'
I have tested now workarounds (from this answer (I have corrected it for vertical using) and from this answer) which were linked in Munim Munna comment and both workarounds do not work correctly (very very buggy).
Workaround with tolerance: 'pointer'
You have to set tolerance: 'pointer'
along with cursorAt: {top: height/2, left: width/2}
(the half size from the width and height of your draggable element).
tolerance : 'pointer'
option allows the element to replace the target element immediately as soon as the cursor enters the target element. By default it was setted to tolerance : 'intersect'
which means that the item overlaps the other item by at least 50%. But unfortunately there is a bug for this option (see the top of my answer).
Try also to use it with and without cursorAt
option or to change the value. This option moves the sorting element or helper so the cursor always appears to drag from the same position. Coordinates can be given as a hash using a combination of one or two keys: {top, left, right, bottom}
.
Here is the documentation for tolerance
option and for cursorAt
option.
Update from 29.01.2019
I have fixed some bugs from jQuery UI Sortable: on dragging from last item if after it it has not enough space for moving. I have fixed this bug with adding this code:
<div style="clear: both; line-height: 500px"> </div>
directly after sortable element.
var startIndex, changeIndex, uiHeight,
bRect = $("ul li")[0].getBoundingClientRect(),
width = bRect.right - bRect.left,
height = bRect.bottom - bRect.top;
$('ul').sortable(
{
tolerance: 'pointer',
cursorAt: {top: height/2, left: width/2}, //try to use it with and without this option
'placeholder': 'marker',
start: function(e, ui)
{
startIndex = ui.placeholder.index();
uiHeight = ui.item.outerHeight(true); //get offset incl margin
ui.item.nextAll('li:not(.marker)').css({
transform: 'translateY(' + uiHeight + 'px)'
});
ui.placeholder.css({height:0, padding:0});
},
change: function(e, ui)
{
changeIndex = ui.placeholder.index();
if(startIndex > changeIndex)
{
var slice = $('ul li').slice(changeIndex, $('ul li').length);
slice.not('.ui-sortable-helper').each(function()
{
var item = $(this);
item.css({
background:'lightcoral',
transform: 'translateY(' +uiHeight+ 'px)'
});
});
}
else if(startIndex < changeIndex)
{
var slice = $('ul li').slice(startIndex, changeIndex);
slice.not('.ui-sortable-helper').each(function()
{
var item = $(this);
item.css({
background: 'lightgreen',
transform: 'translateY(0px)'
});
});
}
startIndex = changeIndex
},
stop: function(e, ui)
{
$('.ui-sortable-handle').css({
background: 'lightblue',
transform: 'translateY(0)'
})
}
});
body{color:white; font-family:Helveticasans-serif; padding:10px}
ul{float:left; width:300px; border-radius:6px}
ul:after{clear:both; content:''; display:table}
li
{
background: lightblue;
display: block;
position: relative;
padding: 80px 6px;
z-index: 1;
margin: 5px 20px;
overflow: hidden;
transition: transform .2s
}
.marker{opacity:0.0; transition:.2s height}
.ui-sortable-helper{transform:scale(.9)}
<br><br>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
<!--
Fixing some bugs from jQuery UI Sortable:
on dragging from last item if after it
it has not enough space for moving
-->
<div style="clear: both; line-height: 500px"> </div>
<!--END of Fixing bugs-->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
It is more useful to see this code snippet in full page (use the link at top of the right from snippet).
推荐阅读
- typescript - 从没有“as const”的数组创建类型元组
- javascript - JavaScript replace() 方法替换错误字符
- tensorflow - Keras model_to_estimator 不在 estimator.train 上记录指标,而是在 estimator.evaluate 上记录
- swift - 当视图控制器从 nib 文件加载时,以模态方式在当前上下文中呈现视图控制器
- mysql - MariaDB/Galera:将 MariaDB 10.4 节点连接到 MariaDB 10.1 集群是否安全?
- android - Cordova 不断用默认的 Hello World 应用程序替换我的代码
- javascript - 找不到模块'conductor-client'已经安装了模块?
- c++ - 如何在方法中使用本地类中的类成员?
- java - AlarmManager 在 Oreo 中安排长时间任务的替代方法是什么?
- mysql - 在 MySQL 与 Oracle 中创建表