js拖拽实现
基本拖拽实现
HTML结构需要一个可拖拽元素:
<div id="draggable" style="width: 100px; height: 100px; background: #ccc;"></div>
JavaScript实现核心逻辑:
const draggable = document.getElementById('draggable');
let isDragging = false;
let offsetX, offsetY;
draggable.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - draggable.getBoundingClientRect().left;
offsetY = e.clientY - draggable.getBoundingClientRect().top;
draggable.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
draggable.style.left = `${e.clientX - offsetX}px`;
draggable.style.top = `${e.clientY - offsetY}px`;
});
document.addEventListener('mouseup', () => {
isDragging = false;
draggable.style.cursor = 'grab';
});
边界限制
防止元素被拖出视口:
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const x = e.clientX - offsetX;
const y = e.clientY - offsetY;
const maxX = window.innerWidth - draggable.offsetWidth;
const maxY = window.innerHeight - draggable.offsetHeight;
draggable.style.left = `${Math.max(0, Math.min(x, maxX))}px`;
draggable.style.top = `${Math.max(0, Math.min(y, maxY))}px`;
});
拖拽事件优化
添加CSS提升体验:
#draggable {
position: absolute;
cursor: grab;
user-select: none;
touch-action: none;
}
移动端适配
添加触摸事件支持:
draggable.addEventListener('touchstart', (e) => {
isDragging = true;
const touch = e.touches[0];
offsetX = touch.clientX - draggable.getBoundingClientRect().left;
offsetY = touch.clientY - draggable.getBoundingClientRect().top;
});
document.addEventListener('touchmove', (e) => {
if (!isDragging) return;
const touch = e.touches[0];
draggable.style.left = `${touch.clientX - offsetX}px`;
draggable.style.top = `${touch.clientY - offsetY}px`;
});
document.addEventListener('touchend', () => {
isDragging = false;
});
拖拽排序实现
列表项拖拽排序示例:

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






