JavaScript Как динамически перемещать Div, щелкая и перетаскивая
Хорошо, казалось бы, все должно быть просто. Мне нужно взять уже существующий div и переместить его в соответствии с положением мыши в окне. Я искал везде, и это привело меня к слишком сложным способам сделать то же самое и связано с использованием j-запроса. Мне нужно строго использовать JavaScript для того, что я пытаюсь сделать.
Метод:
var mousePosition;
var div;
(function createDiv(){
div = document.createElement("div");
div.style.position = "absolute";
div.style.left = "0px";
div.style.top = "0px";
div.style.width = "100px";
div.style.height = "100px";
div.style.background = "red";
div.style.color = "blue";
div.addEventListener('mousedown', handleKeyPressed, true);
document.body.appendChild(div);
})();
function handleKeyPressed(event) {
event.preventDefault();
mousePosition = {
x : event.clientX,
y : event.clientY
};
div.style.left = mousePosition.x;
div.style.top = mousePosition.y;
//alert("whoa!");
}
9 ответов
Я думаю, что вы ищете что-то более подобное
var mousePosition;
var offset = [0,0];
var div;
var isDown = false;
div = document.createElement("div");
div.style.position = "absolute";
div.style.left = "0px";
div.style.top = "0px";
div.style.width = "100px";
div.style.height = "100px";
div.style.background = "red";
div.style.color = "blue";
document.body.appendChild(div);
div.addEventListener('mousedown', function(e) {
isDown = true;
offset = [
div.offsetLeft - e.clientX,
div.offsetTop - e.clientY
];
}, true);
document.addEventListener('mouseup', function() {
isDown = false;
}, true);
document.addEventListener('mousemove', function(event) {
event.preventDefault();
if (isDown) {
mousePosition = {
x : event.clientX,
y : event.clientY
};
div.style.left = (mousePosition.x + offset[0]) + 'px';
div.style.top = (mousePosition.y + offset[1]) + 'px';
}
}, true);
Поддержка сенсорного ввода
Все остальные ответы (включая принятый) не работают с сенсорным вводом. Сенсорные входы имеют события, отличные от событий мыши. См. Использование событий касания в MDN.
Следующий фрагмент кода работает даже при сенсорном вводе. Я выделил все строки кода, которые необходимо добавить для поддержки сенсорных устройств.
Основная идея здесь в том, что каждый элемент, содержащийdraggable
в списке классов должен быть перетаскиваемым. Этой концепции легче следовать, когда у вас есть большое количество элементов, которые нужно перетащить.
См. Эту страницу о сбоях и демонстрацию ниже.
const d = document.getElementsByClassName("draggable");
for (let i = 0; i < d.length; i++) {
d[i].style.position = "relative";
}
function filter(e) {
let target = e.target;
if (!target.classList.contains("draggable")) {
return;
}
target.moving = true;
//NOTICE THIS
e.clientX ?
(target.oldX = e.clientX,
target.oldY = e.clientY) :
(target.oldX = e.touches[0].clientX,
target.oldY = e.touches[0].clientY)
//NOTICE THIS Since there can be multiple touches, you need to mention which touch to look for, we are using the first touch only in this case
target.oldLeft = window.getComputedStyle(target).getPropertyValue('left').split('px')[0] * 1;
target.oldTop = window.getComputedStyle(target).getPropertyValue('top').split('px')[0] * 1;
document.onmousemove = dr;
//NOTICE THIS
document.addEventListener('touchmove', dr, {passive: false})
//NOTICE THIS
function dr(event) {
event.preventDefault();
if (!target.moving) {
return;
}
//NOTICE THIS
event.clientX ?
(target.distX = event.clientX - target.oldX,
target.distY = event.clientY - target.oldY) :
(target.distX = event.touches[0].clientX - target.oldX,
target.distY = event.touches[0].clientY - target.oldY)
//NOTICE THIS
target.style.left = target.oldLeft + target.distX + "px";
target.style.top = target.oldTop + target.distY + "px";
}
function endDrag() {
target.moving = false;
}
target.onmouseup = endDrag;
//NOTICE THIS
target.ontouchend = endDrag;
//NOTICE THIS
}
document.onmousedown = filter;
//NOTICE THIS
document.ontouchstart = filter;
//NOTICE THIS
.draggable {
width: 100px;
height: 100px;
background: red;
}
<div class="draggable"></div>
Проверьте, что это более гладко, чем аденео: FIDDLE
var m = document.getElementById('move');
m.addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
function mouseUp() {
window.removeEventListener('mousemove', move, true);
}
function mouseDown(e) {
window.addEventListener('mousemove', move, true);
}
function move(e) {
m.style.top = e.clientY + 'px';
m.style.left = e.clientX + 'px';
};
Я только что внес небольшое изменение в очень хорошо работающий ответ @adeneo. Если все заключено в функцию, и каждое событие присоединено к div, вы можете использовать его как часть библиотеки.
Вызовите следующую функцию, передавая идентификатор. Если div не существует, он создается.
function drag_div(div_id){
var div;
div = document.getElementById(div_id);
if(div == null){
div = document.createElement("div");
div.id = div_id;
div.style.position = "absolute";
div.style.left = "0px";
div.style.top = "0px";
div.style.width = "100px";
div.style.height = "100px";
div.style.background = "red";
div.style.color = "blue";
document.body.appendChild(div);
}
div.addEventListener('mousedown', function(e) {
div.isDown = true;
div.offset = [
div.offsetLeft - e.clientX,
div.offsetTop - e.clientY
];
}, true);
div.addEventListener('mouseup', function() {
div.isDown = false;
}, true);
div.addEventListener('mousemove', function(event) {
event.preventDefault();
if (div.isDown) {
div.mousePosition = {
x : event.clientX,
y : event.clientY
};
div.style.left = (div.mousePosition.x + div.offset[0]) + 'px';
div.style.top = (div.mousePosition.y + div.offset[1]) + 'px';
}
}, true);
}
JQuery гораздо проще развернуть. Я удивлен, что вы говорите, что не хотите этому учиться.
Вы можете сохранить файл jquery на своем локальном компьютере, чтобы вам не понадобился интернет для использования функций jquery.
В моем случае я сохранил его в папке инструментов. Так что мне не нужно быть в интернете.
Для всех js многих строк js-кода, отвеченных выше, вам нужна только одна маленькая строка.
<script src="/common/tools/jquery-1.10.2.js"></script>
<script src="/common/tools/jquery-ui.js"></script>
<script>
$(function() {
$( "#mydiv_to_make_draggable" ).draggable();
});
</script>
Вы можете использовать его как библиотеку. Прекрасно работает. Я нашел его на github, но иногда он зависал, потому что участник помещал "mouseup" в элемент. Я изменил его на документ, и проблема была устранена. Это исправленная версия
'use strict';
/**
* Makes an element draggable.
*
* @param {HTMLElement} element - The element.
*/
function draggable(element) {
var isMouseDown = false;
// initial mouse X and Y for `mousedown`
var mouseX;
var mouseY;
// element X and Y before and after move
var elementX = 0;
var elementY = 0;
// mouse button down over the element
element.addEventListener('mousedown', onMouseDown);
/**
* Listens to `mousedown` event.
*
* @param {Object} event - The event.
*/
function onMouseDown(event) {
mouseX = event.clientX;
mouseY = event.clientY;
isMouseDown = true;
}
// mouse button released
document.addEventListener('mouseup', onMouseUp);
/**
* Listens to `mouseup` event.
*
* @param {Object} event - The event.
*/
function onMouseUp(event) {
isMouseDown = false;
elementX = parseInt(element.style.left) || 0;
elementY = parseInt(element.style.top) || 0;
}
// need to attach to the entire document
// in order to take full width and height
// this ensures the element keeps up with the mouse
document.addEventListener('mousemove', onMouseMove);
/**
* Listens to `mousemove` event.
*
* @param {Object} event - The event.
*/
function onMouseMove(event) {
if (!isMouseDown) return;
var deltaX = event.clientX - mouseX;
var deltaY = event.clientY - mouseY;
element.style.left = elementX + deltaX + 'px';
element.style.top = elementY + deltaY + 'px';
}
}
Вот еще один подход, включающий сенсорный ввод.
dragElement(document.getElementById('mydiv'));
function dragElement(element) {
var startX = 0, startY = 0, endX = 0, endY = 0;
element.onmousedown = dragStart;
element.ontouchstart = dragStart;
function dragStart(e) {
e = e || window.event;
e.preventDefault();
// mouse cursor position at start
if (e.clientX) { // mousemove
startX = e.clientX;
startY = e.clientY;
} else { // touchmove - assuming a single touchpoint
startX = e.touches[0].clientX
startY = e.touches[0].clientY
}
document.onmouseup = dragStop;
document.ontouchend = dragStop;
document.onmousemove = elementDrag; // call whenever the cursor moves
document.ontouchmove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate new cursor position
if (e.clientX) {
endX = startX - e.clientX;
endY = startY - e.clientY;
startX = e.clientX;
startY = e.clientY;
} else {
endX = startX - e.touches[0].clientX;
endY = startY - e.touches[0].clientY;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
}
// set the new position
element.style.left = (element.offsetLeft - endX) + "px";
element.style.top = (element.offsetTop - endY) + "px";
}
function dragStop() {
// stop moving on touch end / mouse btn is released
document.onmouseup = null;
document.onmousemove = null;
document.ontouchend = null;
document.ontouchmove = null;
}
}
Поздно на вечеринку, но вот что я считаю более простой и удобной для сенсорного управления реализацией:
- Используйте события "указатель вниз/перемещение/вверх" .
Кроме того, нет необходимости постоянно прослушивать события mousemove и использовать логические значения, такие какisMove
и т. д. Вместо этого прикрепите события перемещения и вверх к указателю вниз и используйте Element.removeEventListener к указателю , чтобы отсоединить прослушиватели от окна . - Используйте CSS
touch-action: none;
чтобы события указателя работали на сенсорном устройстве - Вместо сохранения координат начала перетаскивания используйте Event.movementX,Y для текущего элемента Element.offsetLeft/Top.
Принятый ответ с добавлением касания
Принятый ответ от adeneo действительно элегантен и хорошо работает. Однако он работает только для щелчков мышью, поэтому вот исправленная версия, которая включает сенсорный ввод:
var position;
var offset = [0,0];
var isDown = false;
function makeDraggable(el){
['mousedown', 'touchstart'].forEach( evt =>
el.addEventListener(evt, pickup, true)
);
['mousemove', 'touchmove'].forEach( evt =>
el.addEventListener(evt, move, true)
);
['mouseup', 'touchend'].forEach( evt =>
el.addEventListener(evt, drop, true)
);
function pickup(e) {
isDown = true;
if (e.clientX) {
offset = [el.offsetLeft - e.clientX, el.offsetTop - e.clientY];
}
else if (e.touches) {
// for touch devices, use 1st touch only
offset = [el.offsetLeft - e.touches[0].pageX, el.offsetTop - e.touches[0].pageY];
}
}
function move(e) {
if (isDown) {
if (e.clientX) {
position = {x : e.clientX, y : e.clientY};
}
else if (e.touches) {
position = {x : e.touches[0].pageX, y : e.touches[0].pageY};
}
el.style.left = (position.x + offset[0]) + 'px';
el.style.top = (position.y + offset[1]) + 'px';
}
}
function drop(e) {
// seems not to be needed for Android Chrome
// and modern browsers on Mac & PC
// but is required for iPad & iPhone
isDown = false;
el.style.left = (position.x + offset[0]) + 'px';
el.style.top = (position.y + offset[1]) + 'px';
}
}