Мышь: Drag’n’Drop
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/mouse-drag-and-drop.
Drag’n’Drop – это возможность захватить мышью элемент и перенести его. В своё время это было замечательным открытием в области интерфейсов, которое позволило упростить большое количество операций.
Перенос мышкой может заменить целую последовательность кликов. И, самое главное, он упрощает внешний вид интерфейса: функции, реализуемые через Drag’n’Drop, в ином случае потребовали бы дополнительных полей, виджетов и т.п.
Отличия от HTML5 Drag’n’Drop
В современном стандарте HTML5 есть поддержка Drag’n’Drop при помощи специальных событий.
Эти события поддерживаются всеми современными браузерами, и у них есть свои интересные особенности, например, можно перетащить файл в браузер, так что JS получит доступ к его содержимому. Они заслуживают отдельного рассмотрения.
Но в плане именно Drag’n’Drop у них есть существенные ограничения. Например, нельзя организовать перенос «только по горизонтали» или «только по вертикали». Также нельзя ограничить перенос внутри заданной зоны. Есть и другие интерфейсные задачи, которые такими встроенными событиями нереализуемы.
Поэтому здесь мы будем рассматривать Drag’n’Drop при помощи событий мыши.
Рассматриваемые приёмы, вообще говоря, применяются не только в Drag’n’Drop, но и для любых интерфейсных взаимодействий вида «захватить – потянуть – отпустить».
Алгоритм Drag’n’Drop
Основной алгоритм Drag’n’Drop выглядит так:
- Отслеживаем нажатие кнопки мыши на переносимом элементе при помощи события mousedown .
- При нажатии – подготовить элемент к перемещению.
- Далее отслеживаем движение мыши через mousemove и передвигаем переносимый элемент на новые координаты путём смены left/top и position:absolute .
- При отпускании кнопки мыши, то есть наступлении события mouseup – остановить перенос элемента и произвести все действия, связанные с окончанием Drag’n’Drop.
В следующем примере эти шаги реализованы для переноса мяча:
var ball = document.getElementById('ball'); ball.onmousedown = function(e) < // 1. отследить нажатие // подготовить к перемещению // 2. разместить на том же месте, но в абсолютных координатах ball.style.position = 'absolute'; moveAt(e); // переместим в body, чтобы мяч был точно не внутри position:relative document.body.appendChild(ball); ball.style.zIndex = 1000; // показывать мяч над другими элементами // передвинуть мяч под координаты курсора // и сдвинуть на половину ширины/высоты для центрирования function moveAt(e) < ball.style.left = e.pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = e.pageY - ball.offsetHeight / 2 + 'px'; >// 3, перемещать по экрану document.onmousemove = function(e) < moveAt(e); >// 4. отследить окончание переноса ball.onmouseup = function() < document.onmousemove = null; ball.onmouseup = null; >>
Если запустить этот код, то мы заметим нечто странное. При начале переноса мяч «раздваивается» и переносится не сам мяч, а его «клон».
Это можно увидеть в действии внутри ифрейма:
Попробуйте перенести мяч мышкой и вы увидите описанное, довольно-таки странное, поведение.
Это потому, что браузер имеет свой собственный Drag’n’Drop, который автоматически запускается и вступает в конфликт с нашим. Это происходит именно для картинок и некоторых других элементов.
Его нужно отключить:
ball.ondragstart = function() < return false; >;
Теперь всё будет в порядке.
В действии (внутри ифрейма):
Ещё одна особенность правильного Drag’n’Drop – событие mousemove отслеживается на document , а не на ball .
С первого взгляда кажется, что мышь всегда над мячом и обработчик mousemove можно повесить на сам мяч, а не на документ.
Однако, на самом деле мышь во время переноса не всегда над мячом.
Вспомним, событие mousemove возникает хоть и часто, но не для каждого пикселя. Быстрое движение курсора вызовет mousemove уже не над мячом, а, например, в дальнем конце страницы.
Вот почему мы должны отслеживать mousemove на всём document .
Правильное позиционирование
В примерах выше мяч позиционируется в центре под курсором мыши:
self.style.left = e.pageX - ball.offsetWidth / 2 + 'px'; self.style.top = e.pageY - ball.offsetHeight / 2 + 'px';
Если поставить left/top ровно в pageX/pageY , то мячик прилипнет верхним-левым углом к курсору мыши. Будет некрасиво. Поэтому мы сдвигаем его на половину высоты/ширины, чтобы был центром под мышью. Уже лучше.
Но не идеально. В частности, в самом начале переноса, особенно если мячик «взят» за край – он резко «прыгает» центром под курсор мыши.
Для правильного переноса необходимо, чтобы изначальный сдвиг курсора относительно элемента сохранялся.
Где захватили, за ту «часть элемента» и переносим:

-
Когда человек нажимает на мячик mousedown – курсор сдвинут относительно левого-верхнего угла мяча на расстояние, которое мы обозначим shiftX/shiftY . И нужно при переносе сохранить этот сдвиг. Получить значения shiftX/shiftY легко: достаточно вычесть из координат курсора pageX/pageY левую-верхнюю границу мячика, полученную при помощи функции getCoords. При Drag’n’Drop мы везде используем координаты относительно документа, так как они подходят в большем количестве ситуаций. Конечно же, не проблема перейти к координатам относительно окна, если это понадобится. Достаточно использовать position:fixed , elem.getBoundingClientRect() для определения координат и e.clientX/Y .
// onmousedown shiftX = e.pageX - getCoords(ball).left; shiftY = e.pageY - getCoords(ball).top;
// onmousemove ball.style.left = e.pageX - shiftX + 'px'; ball.style.top = e.pageY - shiftY + 'px';
Итоговый код с правильным позиционированием:
var ball = document.getElementById('ball'); ball.onmousedown = function(e) < var coords = getCoords(ball); var shiftX = e.pageX - coords.left; var shiftY = e.pageY - coords.top; ball.style.position = 'absolute'; document.body.appendChild(ball); moveAt(e); ball.style.zIndex = 1000; // над другими элементами function moveAt(e) < ball.style.left = e.pageX - shiftX + 'px'; ball.style.top = e.pageY - shiftY + 'px'; >document.onmousemove = function(e) < moveAt(e); >; ball.onmouseup = function() < document.onmousemove = null; ball.onmouseup = null; >; > ball.ondragstart = function() < return false; >; function getCoords(elem) < // кроме IE8- var box = elem.getBoundingClientRect(); return < top: box.top + pageYOffset, left: box.left + pageXOffset >; >
В действии (внутри ифрейма):
Различие особенно заметно, если захватить мяч за правый-нижний угол. В предыдущем примере мячик «прыгнет» серединой под курсор, в этом – будет плавно переноситься с текущей позиции.
Итого
Мы рассмотрели «минимальный каркас» Drag’n’Drop .
- События ball.mousedown → document.mousemove → ball.mouseup .
- Передвижение с учётом изначального сдвига shiftX/shiftY .
- Отмена действия браузера по событию dragstart .
На этой основе можно сделать очень многое.
- При mouseup можно обработать окончание переноса, произвести изменения в данных, если они нужны.
- Во время самого переноса можно подсвечивать элементы, над которыми проходит элемент.
- При обработке событий mousedown и mouseup можно использовать делегирование, так что одного обработчика достаточно для управления переносом в зоне с сотнями элементов.
Это и многое другое мы рассмотрим в статье про Drag’n’Drop объектов.
Админу.Ру
Библиотека вебмастера по созданию и продвижению сайта
Что такое Drag and Drop Interface
Говоря о графическом интерфейсе пользователя нельзя не сказать о технологии Drag and Drop (буквально: Тяни и Бросай).

Drag and Drop Interface
Данная технология основана на перетаскивании элементов графического интерфейса из источника в приёмник. Интерфейс доступен только с помощью манипулятора мышь (тачпад, трекбол) или сенсорного экрана.
Элемент, доступный для перетаскивания, захватывают и удерживают мышкой, перетаскивая одновременно в другое место. Когда мышь установлена в правильную позицию, кнопку мыши отпускают, освобождая объект.
Следует однако отличать интерфейс Drag’n Drop от элементов управления интерфейсом, имеющими в своих методах методы, отвечающие за перемещение, реализуемые тем же способом. Например, окно (форма) имеет возможность перемещения по экрану (перетаскиванием за область заголовка). ScrollBox имеет ползунок прокрутки. Но в обоих примерах перетаскивание является внутренним (для компонента) действием (событием) и никаким образом не влияет на другие объекты системы.
Drag and Drop интерфейс применим только для перемещения объекта из контейнера в контейнер, даже в том случае, если контейнеры разнородные. Например, перетаскивание файла из папки в письмо Яндекс.Почты.
Drag and Drop интерфейс в веб-технологиях
Использование интерфейсов Drag and Drop в веб-технологиях стало прорывом в WYSIWYG-редакторах. Существуют оффлайн Drag and Drop редакторы (например, DreamWeaver) и онлайн (например, любой современный конструктор сайтов: WiX, NetHouse, Weebly, Setup, Zyro). Даже для изначально текстового редактора страниц WordPress есть плагин Drag and Drop Visual Editor, позволяющий методом перетаскивания создавать великолепные посадочные страницы и сайты-одностраничники.
Метод Drag-and-drop: определение, технология и функции
![]()
Теперь вы знаете, что такое drag-and-drop — это технология, которая помогает облегчить взаимопонимание между пользователем и компьютером или программированием. В последнее время «перетаскивание» блоков стало очень популярным в веб-разработке. Большинство пользователей слышали про такие сервисы , как «Wix» или «Tilda». Они позволяют создавать сайты без знания программирования. О чем говорить, если даже в такой популярной профессиональной CMS, как WordPress, при помощи плагинов также организован а drag-and-drop-технология постройки сайтов. А более мелких реализаций «драг энд дроп» пруд пруди.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Метод создания DRAG and DROP эффекта
Придя впервые к технологии DRAG and DROP столкнулся с очень тяжелым её описанием (Это мое субъективное мнение. Прошу с ним не соглашаться, а перечитать все что только можно и посмотреть на этот вопрос с многих сторон). И решил написать пару статей, нацеленных на начинающих разработчиков, кто хочет познать дзен.
Статья будет состоять из двух частей:
- Метод создания DRAG and DROP эффектов.
- Практическое применение полученных знаний для создание сортировки при помощи DRAG and DROP
Параграф №1 Метод создания DRAG and DROP эффекта
Перед началом глубокого разбора, посмотрим поверхностно. Представьте себя в роли грузчика, вам необходимо перемесить коробку с одного места на другое. Для грузчика это «Ну взял, ну перенес. Готово!», а для программиста “Подошел к коробке, наклонился, взял коробку, поднял коробку, прошел N шагов, наклонился, отпустил коробку.”. Я это к тому, что перед началом работы проиграйте все в голове, по шагам и вы станете гораздо ближе к истине.
Я хочу оговориться, что методов создания данного эффекта несколько и обязательно прочтите о всех. Я воспользуюсь тем, который на данный момент считаю самым удобным.
При создании DRAG and DROP первым шагом необходимо объекту, который мы будем перемещать, присвоить значение draggable=’true’.
.ddd Pervii 1
,
На первом этапе я хочу показать сам процесс, а после мы его распространим на все объекты. Мы сейчас работаем в JS и как вам известно, в браузере существуют различные события, к которым мы можем привязать свои последовательности действий. Давайте разберем необходимые события для создания DRAG and DROP:
dragstart — происходит, когда пользователь начинает перетаскивать элемент.
drag — происходит, когда элемент перетаскивается.
dragend — происходит, когда пользователь закончил перетаскивание элемента.
dragenter — происходит, когда перетаскиваемый элемент попадает в целевой объект.
dragleave — происходит, когда перетаскиваемый элемент покидает целевой объект.
dragover — происходит, когда перетаскиваемый элемент находится над целью.
drop — происходит, когда перетаскиваемый элемент падает на целевой объект.
Теперь очень важная информация! События делятся на две группы. Для перемещаемого элемента (тот кого мы перетаскиваем): dragstart, Drag, Dragend. Для принимающего элемента (куда перетаскиваем): Dragenter, Dragleave, Dragover, Drop. И эти события не могут работать наоборот, но они могут работать друг без друга.
К примеру: Необходимо переместить объект и оставить его там, где мы отпустили кнопку мыши. Эта задача не требует принимающей части.
.ddd Pervii 1 Vtoroy 2 Tretii 3 Chetverty 4 Pyatii 5
Бесспорно, пример сделан на коленке, но он замечательно иллюстрирует не обязательность принимающего объекта.
Параграф №2. Не работает DROP в DRAG and DROP
Когда вы попробуете все события, вы обнаружите что drop не работает. Это разработчики данного метода делают атата тем, кто решил «И это всё… Хух, ерунда».
Ну тут все просто, перед событием drop необходимо на этот же элемент повесить событие
d2.addEventListener('dragover',function() < event.preventDefault(); >);