js实现drag
实现基本的拖拽功能
使用JavaScript实现拖拽功能需要处理三个主要事件:mousedown、mousemove和mouseup。以下是基本实现代码:
const draggableElement = document.getElementById('draggable');
let isDragging = false;
let offsetX, offsetY;
draggableElement.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - draggableElement.getBoundingClientRect().left;
offsetY = e.clientY - draggableElement.getBoundingClientRect().top;
draggableElement.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
draggableElement.style.left = `${e.clientX - offsetX}px`;
draggableElement.style.top = `${e.clientY - offsetY}px`;
});
document.addEventListener('mouseup', () => {
isDragging = false;
draggableElement.style.cursor = 'grab';
});
添加CSS样式
确保拖拽元素有正确的CSS定位:
#draggable {
position: absolute;
cursor: grab;
user-select: none;
width: 100px;
height: 100px;
background-color: #3498db;
}
处理边界限制
防止元素被拖出视口:
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
let newX = e.clientX - offsetX;
let newY = e.clientY - offsetY;
// 限制在视口范围内
newX = Math.max(0, Math.min(newX, window.innerWidth - draggableElement.offsetWidth));
newY = Math.max(0, Math.min(newY, window.innerHeight - draggableElement.offsetHeight));
draggableElement.style.left = `${newX}px`;
draggableElement.style.top = `${newY}px`;
});
使用HTML5 Drag API
HTML5提供了原生拖拽API,实现更简单:
const draggable = document.getElementById('draggable');
draggable.setAttribute('draggable', 'true');
draggable.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', draggable.id);
e.dataTransfer.effectAllowed = 'move';
});
document.addEventListener('dragover', (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
});
document.addEventListener('drop', (e) => {
e.preventDefault();
const id = e.dataTransfer.getData('text/plain');
const element = document.getElementById(id);
element.style.left = `${e.clientX - element.offsetWidth/2}px`;
element.style.top = `${e.clientY - element.offsetHeight/2}px`;
});
拖拽排序实现
实现列表项拖拽排序:

const list = document.getElementById('sortable-list');
let draggedItem = null;
list.addEventListener('dragstart', (e) => {
draggedItem = e.target;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', e.target.innerHTML);
setTimeout(() => e.target.classList.add('dragging'), 0);
});
list.addEventListener('dragover', (e) => {
e.preventDefault();
const afterElement = getDragAfterElement(list, e.clientY);
if (afterElement == null) {
list.appendChild(draggedItem);
} else {
list.insertBefore(draggedItem, afterElement);
}
});
list.addEventListener('dragend', (e) => {
e.target.classList.remove('dragging');
});
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('li:not(.dragging)')];
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
} else {
return closest;
}
}, { offset: Number.NEGATIVE_INFINITY }).element;
}






