jQueryUI сортировка и скорость перетаскивания - PullRequest
8 голосов
/ 15 марта 2019

У меня есть список, который использует сортировку jQueryUI.Мне нужно отслеживать каждый шаг элемента во время перетаскивания, основываясь на событии «изменения» плагина.

Но он надежно работает только от медленного, до обычного перетаскивания.При этих скоростях нет никакой ошибки.Но если пользователь перетаскивает элемент относительно быстро (чем больше список, тем чаще это происходит, потому что у мыши больше места для увеличения скорости), событие «изменения» теряет некоторые шаги и, таким образом, некоторая полезная информация теряется вместе с ним.путь без ошибок выдается в консоль.

Отображение проблемы:

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

В этом jsFiddle вы можете перетащить элементи посмотрите его изменение индекса как пример .Под списком, при перетаскивании, у вас будет эмуляция консоли, отслеживающая индексы в черном .

Если перетащить достаточно быстро, вы увидите, что некоторые из этих индексов станут красный .Это проблема.Это означает, что сортируемый скрипт упускает их предыдущую позицию во время события изменения по причине, которую я просто не понимаю.Преемственность нарушена, и эта преемственность изначально для моих нужд.Скорость - единственное, что нарушает непрерывность.Но событие «изменения», которое не может сравниться с достаточно быстрым перетаскиванием мыши, кажется довольно странным.

enter image description here

Сценарий:

Половина из этого посвящена отслеживанию индекса, поскольку у Sortable есть особый способ ссылки на индексы, который зависит от направления (вверх / вниз), но ТАКЖЕ от текущей позиции элемента относительно его начальнойположение (до / после).Таким образом, для визуального понимания этих индексов требуется минимальное количество кода.С помощью этого сценария элемент получает визуальный индекс, который интуитивно тот, который вы ожидаете увидеть, упорядоченным образом.

Однако этот сценарий является демонстрацией проблемы, вероятно, не проблемы (см.примечание ниже).

Другая половина скрипта как раз о эмуляции своего рода консоли для отладки.

Мои догадки:

Возможно, я ошибаюсь, но в итоге думаю, что это проблема отслеживания с событием «change» или что перетаскиваемый элемент не поспевает за курсором мыши (кажется, что он не всегда находится под курсором при относительно высоких скоростях),Если нет возможности использовать Sortable, о котором я не знаю ...

Я думаю, что это один из тех сценариев, потому что любой код, который я пытаюсь использовать внутри события "change", всегда приводит кэта проблема разрыва.

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();
    }
});

Примечание:

Весь код внутри события "change" адаптирован для вас, чтобы ВИДЕТЬпроблема, вероятно, не проблема сама по себе.Я позволю вам быть судьей в этом, но это справедливо упомянуть об этом.

Мой настоящий сценарий в разделе изменений отличается.Это вызывает переупорядочение некоторых столбцов таблицы, и именно так я впервые обнаружил проблему, поскольку при переупорядочении таблиц возникают глюки на высоких скоростях.Таким образом, фиктивный сценарий здесь - это только я сужая его до минимума, в то время как показывает вам проблему визуально.

Суть в том, чтобы оценить, является ли этопроблема с производительностью, которая может быть решена, отсутствие опции Sortable, которую я должен добавить, задержка перетаскивания / перемещения курсора, которую можно исправить, или если есть какой-то прием, чтобы как-то обойти эту проблему отслеживания.

Я думаю, что это справедливопредупреждение, чтобы предотвратить вас от отладки фиктивного сценария, который является просто витриной.Но, учитывая, что я новичок и могу ошибаться, делайте так, как считаете нужным.

Во всех случаях ваша помощь или вклад будут очень благодарны.Заранее спасибо.

РЕДАКТИРОВАТЬ: Вот мой реальный (суженный) скрипт, подающий событие «dataTable.colReorder.move». Он более сложен, так как ему необходимо знать индекс посадки (a / b), а также текущий индекс перетаскиваемого элемента (a / b / c / d). И сортируемый имеет свой собственный ситуационный способ индексировать это.

$( ".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);       
    }
});

Ответы [ 2 ]

4 голосов
/ 22 марта 2019

Некоторые наблюдения из предыдущего ответа верны, но вот мое зерно соли. Кстати, я считаю, что это "поправимо" ..

На мой взгляд, есть очень простое решение. Каждый раз, когда происходит «пропуск», сортируемый не скажет вам все промежуточные шаги, так что ... почему вы их не строите? ..

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();
    }
});

Как вы можете видеть здесь, если произойдет пропуск, я просто добавлю к информации var все шаги, пропущенные событием изменения ... однако, к сожалению, это все еще не работает .. причина проста .. повторный вход в событие изменения.

Теперь у меня не было времени, чтобы написать работающее решение, но это моя идея. Вы должны перестраивать список с отсутствующими промежуточными значениями каждый раз, когда заканчивается событие изменения. Таким образом, вы можете иметь непрерывную последовательность. Итак, из вашего исходного кода просто добавьте к событию остановки метод, который на основе последовательности, созданной изменением, заполняет промежуточные значения и вуаля, у вас есть ваша последовательность.

Дайте мне знать, если это удовлетворяет вашим требованиям.

4 голосов
/ 22 марта 2019

К сожалению ... нет решения , чтобы решить эту проблему.

Сначала я попытался использовать 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
Все, что я сказал выше, все еще верно ... Но поскольку у вас уже есть "обнаружение пропуска" , почему бы не использовать его для заполнения пробелов?

У вас было 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>

Скрипка

...