jQueryUI可排序和拖动速度问题

问题描述 投票:7回答:2

我有一个使用jQueryUI可排序的列表。我需要根据插件的“更改”事件跟踪拖动元素的每个步骤。

但它只能从缓慢,高达正常的拖动中可靠地工作。在那些速度下,没有任何错误。但是如果用户相对快速地拖动元素(列表越大,它将发生的次数越多,因为鼠标有更大的空间来获得速度),“更改”事件会丢失一些步骤,因此,一些有用的信息会丢失在控制台中没有抛出错误的方式。

显示问题:

https://jsfiddle.net/yhp3m6L8/2/

在这个jsFiddle中,您可以拖动一个元素并查看其索引更改作为示例。在列表下方,在拖动时,您将拥有一个控制台仿真,以黑色跟踪索引。

如果拖得相当快,你会看到其中一些索引变成红色。这就是问题。这意味着他们之前的位置在更改事件期间被可排序脚本忽略了,原因是我没有得到。连续性被打破,这种连续性是我的需要的基础。速度是唯一打破连续性的因素。但是,一个无法跟上相当快的鼠标阻力的“改变”事件似乎很奇怪。

enter image description here

剧本:

其中一半是关于跟踪索引,因为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);       
    }
});
jquery performance jquery-ui jquery-ui-sortable onchange
2个回答
4
投票

可悲的是......没有解决方案可以解决这个问题。

我第一次尝试使用sort event callback ......同样的“跳过”问题发生在非常快速的拖拽上。

我想知道为什么几分钟...... 然后我教会了.sortable()可能依赖的东西......我带来了唯一可能的“浏览器”事件:mousemove

虽然mousemove经常发射......就像一把“机关枪”......它并没有为你在这里的预期而快速射击。

为了验证这一点,我只是在你未改变的小提琴的末尾添加了这个mousemove处理程序:

$( ".panel_list" ).on("mousemove",function(e){
  console.log($(e.target).index());
});

它记录的是与div.console完全相同的数字。

enter image description here

所以问题不是由于.sortable()肯定。


EDIT
All I said above is still true... But since you already have the "skip detection", why not use it to fill the gaps?

你有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>';
  };
}


It deserves a snippet... For posterity. (Run in ful page mode.)

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>

Fiddle


4
投票

前一个答案中的一些观察是正确的,但这是我的盐。顺便说一句,我相信这是“可以修复的”..

在我看来,这是一个非常简单的解决方案。每次发生“跳过”时,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();
    }
});

正如你在这里看到的,如果发生跳过,我将只添加更改事件错过的所有步骤的信息变量......然而,遗憾的是,这仍然无效......原因很简单......重新进入改变事件。

现在,我没有时间编写工作解决方案,但这是我的想法。每次更改事件结束时,您必须使用缺少的中间值重建列表。这样你就可以有一个连续的序列。因此,从您的原始代码中,只需添加一个基于由更改创建的序列填充中间值的方法,您就可以添加到停止事件中。

如果这符合您的要求,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.