我有一个使用jQueryUI可排序的列表。我需要根据插件的“更改”事件跟踪拖动元素的每个步骤。
但它只能从缓慢,高达正常的拖动中可靠地工作。在那些速度下,没有任何错误。但是如果用户相对快速地拖动元素(列表越大,它将发生的次数越多,因为鼠标有更大的空间来获得速度),“更改”事件会丢失一些步骤,因此,一些有用的信息会丢失在控制台中没有抛出错误的方式。
显示问题:
https://jsfiddle.net/yhp3m6L8/2/
在这个jsFiddle中,您可以拖动一个元素并查看其索引更改作为示例。在列表下方,在拖动时,您将拥有一个控制台仿真,以黑色跟踪索引。
如果拖得相当快,你会看到其中一些索引变成红色。这就是问题。这意味着他们之前的位置在更改事件期间被可排序脚本忽略了,原因是我没有得到。连续性被打破,这种连续性是我的需要的基础。速度是唯一打破连续性的因素。但是,一个无法跟上相当快的鼠标阻力的“改变”事件似乎很奇怪。
剧本:
其中一半是关于跟踪索引,因为Sortable有一种特殊的方式来引用索引,这取决于方向(向上/向下),但也是元素相对于其初始位置(之前/之后)的当前位置。因此,从这些索引中直观地理解所需的代码量很少。使用该脚本,该元素以一种有序的方式获得一个直观的视觉索引,您希望看到它。
但是,这个脚本是问题的展示,可能不是问题(参见下面的旁注)。
该脚本的另一半只是为了调试目的而模拟一种控制台。
我的猜测:
我可能错了,但我最终认为这是“更改”事件的跟踪问题,或者拖动的元素跟不上鼠标光标(感觉它并不总是在光标下以相对较高的速度)。除非有可用的Sortable选项,否则我不知道......
我认为这是其中一个场景,因为无论我尝试在“更改”事件中使用什么代码,我总是会遇到这个差距问题。
HTML:
<html>
<body>
<div class="panel">
<ul class="panel_list">
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="unticked"></li>
<li class="unticked"></li>
<li class="unticked"></li>
</ul>
</div>
<div class='console'></div>
</body>
</html>
CSS:
.console{
width:100%;
}
.panel ul{
list-style-type:none;
width:30%;
}
.panel li{
height:29px;
border-bottom:1px solid #454d5a;
text-align: left;
vertical-align: middle;
line-height:29px;
padding-left:8px;
background: #666;
}
.panel_highlight{
height:29px;
background:#1c2128 !important;
}
.unticked{
color:#7c7a7d;
background:#222 !important;
}
jQuery的:
// jQuery: 3.3.1
// jQueryUI: 1.11.4 (downgraded from 1.12.1, because of documented
// performance issues but...with no effect)
var origValue;
var oldInfo;
var c=0;
var x=0;
// LIST RELATED
//Just to have a visual on the indexes in the list.
$('li').each(function(){
$(this).data('idx',c++);
$(this).text(c);
})
c=0;
$( ".panel_list" ).sortable({
placeholder: 'panel_highlight',
items : '>li.ticked',
cancel : '>li.unticked',
tolerance : 'pointer',
axis : 'y',
opacity : 0.9,
start: function(event, ui){
// LIST RELATED
origValue = ui.item.data('idx');
// CONSOLE RELATED (initialise variables)
$('.console').html('');oldInfo='';
},
change: function(event, ui){
// LIST RELATED
var idx = ui.placeholder.prevAll().filter(':not(.ui-sortable-helper)').length;
var a=ui.placeholder.index();
var b=a+1;
//detect the direction of the dragging
if(idx - $(this).data('idx')==1)
{//downward dragging
//if the element is below its initial position (or x=1)
if((a<=origValue) || (x==1)){ui.item.text(b);x=0;}
//if the element is still above its initial position
else {ui.item.text(a);};
}
else
{//upward dragging
//if the element is still below its initial position
if(a<=origValue) {ui.item.text(b);x=1;}
//if the element is above its initial position
else {ui.item.text(a);};
};
$(this).data('idx', idx);
// Update the visual on the indexes in the list.
$('li').each(function(){
if(ui.item.index() !=$(this).index()){
$(this).data('idx',c++);
$(this).text(c);
}
})
c=0;
// CONSOLE RELATED (show indexes progression and gaps)
var info=$('.console').html();
if(oldInfo !=''){
var valAbs= Math.abs( parseInt(ui.item.text()) - parseInt(oldInfo));
if(valAbs==1){info=info+' + '+ui.item.text();}
else{info=info+' + <span style="color:red">'+ui.item.text()+'</span>';};
}
else{info=ui.item.text();};
$('.console').html(info);
oldInfo = ui.item.text();
}
});
边注:
“更改”事件中的所有代码都是为您量身定制的,以解决问题,可能不是问题本身。我让你成为它的判断,但这是公平的。
我在变更部分的实际脚本是不同的。它触发了一些表格列的重新排序,这就是我第一次检测到问题的方法,因为表格重新排序在高速度下有毛刺。因此,这里的虚拟脚本只是将其缩小到最小,同时以可视方式向您显示问题。
关键在于评估是否可以解决性能问题,缺少可添加的可排序选项,可以修复的拖动/游标延迟,或者是否有任何技巧以某种方式解决此跟踪问题。
我认为这是一个公平的警告,以防止您调试只是一个展示的虚拟脚本的麻烦。但考虑到我只是一个新手,我可能错了,按你认为合适的方式做。
在任何情况下,您的帮助或输入将非常感激。先感谢您。
编辑:这是我的真实(缩小)脚本,提供“dataTable.colReorder.move”事件。它涉及更多,因为它需要知道着陆指数(a / b)以及拖动元素的当前指数(a / b / c / d)。而sortable有自己的情境方式来索引这个。
$( ".panel_list" ).sortable({
placeholder: 'panel_highlight',
items : '>li.ticked',
cancel : '>li.unticked',
start: function(event, ui){
lastValue='';
origValue=ui.item.index();
$(this).data('idx', ui.item.index());
},
change: function(event, ui){
var x;
var idx = ui.placeholder.prevAll().filter(':not(.ui-sortable-helper)').length;
var a= ui.placeholder.index();
var b=a+1;var c=a+2;var d=a-1;
if(idx - $(this).data('idx')==1)
{//downward
if((origValue>=a) || (x==1)){dataTable.colReorder.move(a,b);lastValue=b;x=0}
else {dataTable.colReorder.move(d,a);lastValue=a;}
}
else
{//upward
if(origValue>=a) {dataTable.colReorder.move(c,b);lastValue=b;x=1}
else {dataTable.colReorder.move(b,a);lastValue=a;}
}
$(this).data('idx', idx);
}
});
可悲的是......没有解决方案可以解决这个问题。
我第一次尝试使用sort event callback
......同样的“跳过”问题发生在非常快速的拖拽上。
我想知道为什么几分钟......
然后我教会了.sortable()
可能依赖的东西......我带来了唯一可能的“浏览器”事件:mousemove
。
虽然mousemove
经常发射......就像一把“机关枪”......它并没有为你在这里的预期而快速射击。
为了验证这一点,我只是在你未改变的小提琴的末尾添加了这个mousemove
处理程序:
$( ".panel_list" ).on("mousemove",function(e){
console.log($(e.target).index());
});
它记录的是与div.console
完全相同的数字。
所以问题不是由于.sortable()
肯定。
你有oldInfo
,这是这个新的.index()
之前的最后一个change
。
你有新的.index()
......
根据运动是向上还是向下,您需要一个或另一个for
循环来填补编号中的空白。这也是你对这些数字所做的事情的触发点......
;)
这是改变的部分:
// CONSOLE RELATED
info=$('.console').html();
if(oldInfo !=''){
var valReal = parseInt(ui.item.text()) - parseInt(oldInfo);
var valOld = parseInt(oldInfo);
var valAbs= Math.abs( parseInt(ui.item.text()) - parseInt(oldInfo));
if(valAbs==1){info=info+' + '+ui.item.text();}
else{
// ADDING THE SKIPPED ONES!
// Upward (in blue)
if(valReal>0){
for(i=valOld+1;i<valOld+valReal;i++){
info=info+' + <span style="color:blue">'+( i )+'</span>';
}
// Downward (in green)
}else{
for(i=valOld-1;i>valOld+valReal;i--){
info=info+' + <span style="color:green">'+( i )+'</span>';
}
}
// The one caugth after a gap (in red)
info=info+' + <span style="color:red">'+ui.item.text()+'</span>';
};
}
var origValue;
var oldInfo;
var info;
var c=0;
var x=0;
// LIST RELATED
//With or without this, the problem will occur.
$('li').each(function(){
$(this).data('idx',c++);
$(this).text(c);
})
c=0;
$( ".panel_list" ).sortable({
placeholder: 'panel_highlight',
tolerance : 'pointer',
axis : 'y',
opacity : 0.9,
items : '>li.ticked',
cancel : '>li.unticked',
start: function(event, ui){
// LIST RELATED
origValue = ui.item.data('idx');
// CONSOLE RELATED
$('.console').html(''); oldInfo=''; info='';
},
change: function(event, ui){
// LIST RELATED
var idx = ui.placeholder.prevAll().filter(':not(.ui-sortable-helper)').length;
var a=ui.placeholder.index();
var b=a+1;
if(idx - $(this).data('idx')==1)
{//downward dragging
if((a<=origValue) || (x==1)){ui.item.text(b);x=0;}
else {ui.item.text(a);};
}
else
{//upward dragging
if(a<=origValue) {ui.item.text(b);x=1;}
else {ui.item.text(a);};
};
$(this).data('idx', idx);
//With or without this, the problem will occur.
$('li').each(function(){
if(ui.item.index() !=$(this).index()){
$(this).data('idx',c++);
$(this).text(c);
}
})
c=0;
// CONSOLE RELATED
info=$('.console').html();
if(oldInfo !=''){
var valReal = parseInt(ui.item.text()) - parseInt(oldInfo);
var valOld = parseInt(oldInfo);
var valAbs= Math.abs( parseInt(ui.item.text()) - parseInt(oldInfo));
if(valAbs==1){info=info+' + '+ui.item.text();}
else{
// ADDING THE SKIPPED ONES!
if(valReal>0){
for(i=valOld+1;i<valOld+valReal;i++){
info=info+' + <span style="color:blue">'+( i )+'</span>';
}
}else{
for(i=valOld-1;i>valOld+valReal;i--){
info=info+' + <span style="color:green">'+( i )+'</span>';
}
}
// The one caugth after a gap
info=info+' + <span style="color:red">'+ui.item.text()+'</span>';
};
}
else{info=ui.item.text();};
$('.console').html(info);
oldInfo = ui.item.text();
}
});
.console{
width:100%;
}
.panel ul{
list-style-type:none;
width:30%;
}
.panel li{
height:29px;
border-bottom:1px solid #454d5a;
text-align: left;
vertical-align: middle;
line-height:29px;
padding-left:8px;
background: #666;
}
.panel_highlight{
height:29px;
background:#1c2128 !important;
}
.unticked{
color:#7c7a7d;
background:#222 !important;
}
.ui-sortable-helper{
background-color:red !important;
}
<link href="https://www.lexgotham.com/test5/styles/reset.css" rel="stylesheet"/>
<link href="https://www.lexgotham.com/test5/scripts/jQuery/jquery-ui-1.12.1/jquery-ui.css" rel="stylesheet"/>
<script src="https://www.lexgotham.com/test5/scripts/jQuery/jquery.3.3.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<html>
<body>
<div class="panel">
<ul class="panel_list">
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="ticked"></li>
<li class="unticked"></li>
<li class="unticked"></li>
<li class="unticked"></li>
</ul>
</div>
<div class='console'></div>
</body>
</html>
前一个答案中的一些观察是正确的,但这是我的盐。顺便说一句,我相信这是“可以修复的”..
在我看来,这是一个非常简单的解决方案。每次发生“跳过”时,sortable都不会告诉你所有的中间步骤,所以......为什么不构造它们?
var origValue;
var oldInfo;
var info;
var c=0;
var x=0;
// LIST RELATED
//With or without this, the problem will occur.
$('li').each(function(){
$(this).data('idx',c++);
$(this).text(c);
})
c=0;
$( ".panel_list" ).sortable({
placeholder: 'panel_highlight',
tolerance : 'pointer',
axis : 'y',
opacity : 0.9,
items : '>li.ticked',
cancel : '>li.unticked',
start: function(event, ui){
// LIST RELATED
origValue = ui.item.data('idx');
// CONSOLE RELATED
$('.console').html(''); oldInfo=''; info='';
},
change: function(event, ui){
// LIST RELATED
var idx = ui.placeholder.prevAll().filter(':not(.ui-sortable-helper)').length;
var a=ui.placeholder.index();
var b=a+1;
if(idx - $(this).data('idx')==1)
{//downward dragging
if((a<=origValue) || (x==1)){ui.item.text(b);x=0;}
else {ui.item.text(a);};
}
else
{//upward dragging
if(a<=origValue) {ui.item.text(b);x=1;}
else {ui.item.text(a);};
};
$(this).data('idx', idx);
//With or without this, the problem will occur.
$('li').each(function(){
if(ui.item.index() !=$(this).index()){
$(this).data('idx',c++);
$(this).text(c);
}
})
c=0;
// CONSOLE RELATED
info=$('.console').html();
if(oldInfo !=''){
oIv = parseInt(oldInfo);
uiV = parseInt(ui.item.text());
stepIn = (uiV > oIv ? 1 : -1);
switch (stepIn) {
case 1:
for (i=oIv+1;i<uiV;i++) {info=info+' + <span style="color:green">'+i+'</span>';}
break;
case -1:
for (i=uiV+1;i<=oIv;i++) {info=info+' + <span style="color:red">'+i+'</span>';}
break;
}
}
else{info=ui.item.text();};
$('.console').html(info);
oldInfo = ui.item.text();
}
});
正如你在这里看到的,如果发生跳过,我将只添加更改事件错过的所有步骤的信息变量......然而,遗憾的是,这仍然无效......原因很简单......重新进入改变事件。
现在,我没有时间编写工作解决方案,但这是我的想法。每次更改事件结束时,您必须使用缺少的中间值重建列表。这样你就可以有一个连续的序列。因此,从您的原始代码中,只需添加一个基于由更改创建的序列填充中间值的方法,您就可以添加到停止事件中。
如果这符合您的要求,请告诉我。