Почему данный drag&drop лагает

178
11 ноября 2018, 12:10

Реализовал у себя в проекте поддержку drag&drop функционала для элементов с классом draggable. К сожалению, данная реализация ведет сея иногда странно: элемент иногда начинает "убегать" от курсора и "застревает" при перемещении мышкой.

//window.onload = function() { 
let elements = document.querySelectorAll('.draggable'); 
 
elements.forEach(function(el) { 
  let mover = false, 
    x, y, posx, posy, first = true; 
  document.onmousedown = function() { 
    mover = true; 
  }; 
  document.onmouseup = function() { 
    mover = false; 
    first = true; 
  }; 
  el.onmousemove = function(e) { 
    el.style.cursor = "move"; 
    if (mover) { 
      if (first) { 
        x = e.offsetX; 
        y = e.offsetY; 
        first = false; 
      } 
 
      posx = e.pageX - x; 
      posy = e.pageY - y; 
      el.style.left = posx + 'px'; 
      el.style.top = posy + 'px'; 
    } 
  } 
}); 
//}
html, 
body { 
  height: 100%; 
  margin: 0; 
  padding: 0; 
  overflow: hidden; 
} 
 
body { 
  overflow: auto; 
  /* добавить полосу прокрутки */ 
} 
 
header { 
  height: 60px; 
  background-color: white; 
} 
 
.wrap { 
  display: inline-flex; 
  flex-direction: row; 
  flex-wrap: wrap; 
  justify-content: space-between; 
  align-content: stretch; 
  align-items: flex-start; 
  width: 100%; 
} 
 
.header-link { 
  padding: 1.1em; 
} 
 
.header-h1 { 
  padding-left: 1em; 
} 
 
#header-title { 
  color: #1c5a7d; 
} 
 
.header-link>a { 
  font-weight: 500; 
  color: #888; 
} 
 
.header-link>a:hover { 
  color: #444; 
} 
 
.header-menu-wrapper { 
  display: inline-flex; 
  flex-direction: row; 
  flex-wrap: wrap; 
} 
 
header-h1 { 
  width: 100%; 
  text-align: right; 
  font-size: 26px; 
  float: right; 
} 
 
.botmaker-container { 
  float: right; 
  position: relative; 
  width: 100%; 
  height: 100%; 
  overflow: hidden; 
} 
 
.botmaker-node { 
  width: 100%; 
  height: 100%; 
  max-width: 230px; 
  max-height: 130px; 
  border: 1px solid #333; 
  border-bottom-right-radius: 120px; 
  border-top-right-radius: 120px; 
} 
 
.node-form-input { 
  width: 100%; 
  max-width: 170px; 
} 
 
.draggable { 
  position: absolute; 
  z-index: 1; 
  top: 100px; 
} 
 
.botmaker { 
  min-height: 1000px; 
}
<header> 
  <div class="wrap"> 
    <div id="header-title" class=""> 
      <h1 class="header-h1">Visual bot maker</h1> 
    </div> 
    <div class="header-menu-wrapper"> 
      <div class="wrapper-item header-link"> 
        <a href="">DOCUMENTATION</a> 
      </div> 
      <div class="wrapper-item header-link"> 
        <a href="">FORUM</a> 
      </div> 
      <div class="wrapper-item header-link"> 
        <a href="">SUPPORT</a> 
      </div> 
    </div> 
  </div> 
</header> 
 
<section class="botmaker-container dragscroll"> 
  <div class="botmaker"> 
    <div class="botmaker-node start-node draggable" style="cursor: move; left: 570px; top: 129px;"> 
      <form action="" method="post" class="form-group"> 
        <div class="node-form-input"> 
          <label for="startNode">Phrase</label> 
          <input type="text" class="form-control" id="startNode" placeholder="Start phrase"> 
          <button type="submit" class="btn btn-primary node-submit">Ок</button> 
        </div> 
      </form> 
    </div> 
  </div> 
</section>

Данные баги иногда не удается повторить, но они случаются. Может это не самая лучшая реализация и есть лучший пример drag&drop'a? или в моем случае какой то недочет мешает?

Answer 1

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

Этот код отслеживает положение мыши относительно родителя draggable элемента и ему не важно, под мышью ли он или нет.

let elements = document.querySelectorAll('.draggable');
elements.forEach(function(el) {
  let mover = false,
    x, y, posx, posy, first = true;
  el.onmousedown = function() {
    mover = true;
  };
  el.onmouseup = function() {
    mover = false;
    first = true;
  };
  el.parentNode.onmousemove = function(e) {
    el.style.cursor = "move";
    if (mover) {
      if (first) {
        x = e.offsetX;
        y = e.offsetY;
        first = false;
      }
      posx = e.pageX - x;
      posy = e.pageY - y;
      el.style.left = posx + 'px';
      el.style.top = posy + 'px';
    }
  }
});
READ ALSO
Не cрабатывает событие click на iPhone

Не cрабатывает событие click на iPhone

Знаю, что этот вопрос поднимался множество раз, и на него есть ответы, которые помогли многимНоя перепробовал все предложенные варианты,...

223
Js-jq dublicates .find

Js-jq dublicates .find

jq функция

177
Запись информации из textarea в файл

Запись информации из textarea в файл

Пишу JSP, реализовал считывание файла через java и отображение на разметке(поправьте, если в матчасти ошибся)

190