Обзор

Многие веб-разработчики (Front End) очень запутались в том, как работает система перетаскивания, как на самом деле хорошо реализовать гибкие эффекты перетаскивания, в этом уроке мы рассмотрим создание надежного механизма перетаскивания с использованием собственного Javascript ( Библиотеки не нужны) мы собираемся реализовать все приложение на CodePen, поэтому дальнейшая настройка не требуется, все, что вам нужно сделать, это расслабиться, взять чашку кофе и наслаждаться кодированием.

Структура приложения

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

Итак, вот как будет выглядеть структура приложения, над которой мы будем работать.

<div class="container">
  <div id="items-container" class="base-container">
    <div class="header">Items</div>
    <div class="todo-item">
      TODO Item
    </div>
  </div>
  <div id="todos-container" class="base-container">
    <div class="header">TODO</div>
  </div>
</div>

Кроме того, стиль CSS, который вам может понадобиться для ваших собственных приложений.

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: row; 
  justify-content: space-around;
  align-items: center;
}

.base-container {
  min-width: 300px;
  min-height: 400px;
  //border: 1px solid rgba(15, 15, 15, 0.2);
  box-shadow: 0px 0px 20px 2px rgba(15, 15, 15, 0.2);
  padding: 25px;
}

.header {
  width: 100%;
  font-family: Oxygen, sans-serif;
  font-size: 22px;
  text-align: center;
}

.no-todo-container {
  border: 1px solid rgba(15, 15, 15, 0.2);
  box-shadow: 0px 0px 5px 10px rgba(15, 15, 15, 0.2);
} 

.todo-container {
  border: 1px solid rgba(15, 15, 15, 0.2);
  box-shadow: 0px 0px 5px 10px rgba(15, 15, 15, 0.2);
}

.todo-item {
  //border-bottom: 1px solid ;
  width: 300px;
  height: 20px;
  position: absolute;
  background-color: #F44336;
  color: #FFFFFF;
  font-family: Oxygen, sans-serif;
  font-size: 20px;
  padding: 7px;
  margin: 10px 0 10px 0;
  box-shadow: inset 1px 1px 10px 0 rgba(15, 15, 15, 0.2);
  border-radius: 3px;
  cursor: pointer;
}

.snap {
  width: 301px;
  height: 30px;
  margin-top: 5px;
  margin-bottom: 5px;
}

.over {
  background-color: rgba(15, 15, 15, 0.2);
  border: 2px solid #F44336;
  border-radius: 5px;
}

Давайте начнем

Во-первых, нам нужно ссылаться как на элементы, так и на контейнер задач, а также на элементы задач, используя собственный js.

let itemsContainer = document.getElementById("items-container");

let todosContainer = document.getElementById("todos-container");

let todoItems = document.getElementsByClassName("todo-item");

Поскольку мы собираемся работать с несколькими элементами todo вместо одного, нам нужно пройтись по каждому элементу и обработать перетаскивание мышью конкретно под элементом.

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

мы собираемся создать отдельные обработчики функций для этих событий, чтобы упростить задачу.

//Loop through all Todo Items (Handle all Todo Items Dragging)
for(let i = 0; i < todoItems.length; i++) {
  let item = todoItems[i];
  //Mouse Button Down
  item.addEventListener("mousedown", (e) => { onMouseDown(e, item); });
  //Mouse Move (Under the Page Body since mouse moves right there)
  document.body.addEventListener("mousemove", (e) => {
      onMouseMove(e, item);
  });
  //Mouse Up 
  item.addEventListener("mouseup", (e) => {
    onMouseUp(e, item);
  });
}

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

//Mouse Down
function onMouseDown(e, item) {
  isMouseDown = true;
  
  mouseOffset = {x: item.offsetLeft - e.clientX, y: item.offsetTop - e.clientY};
  
  item.style.backgroundColor = "#E57373";
}
//Mouse Up 
function onMouseUp(e, item) {
  isMouseDown = false;
  item.style.backgroundColor = "#F44336";
}

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

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

function onMouseMove(e, item) {
  e.preventDefault(); ///< Stops the Default Element Bahiavor 
  if(isMouseDown) {
    //Move Item only when mouse is down 
    item.style.left = e.clientX + mouseOffset.x + "px";
    item.style.top = e.clientY + mouseOffset.y + "px";
    //Concatinating Numbers with Strings is Javascript gives you a String
  }
}

Теперь, если вы можете попытаться переместить элемент Todo, вы должны получить очень плавный переход перетаскивания.

Что дальше

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