UNPKG

ele-drag

Version:

一个简单易用的js拖动库

221 lines (188 loc) 7.12 kB
/** * Dragable - 简单易用的拖动库 * 支持移动端和电脑端 * 自动添加到HTMLElement原型 * * 使用方法: * element.enableDrag(); * element.disableDrag(); */ (function() { // 存储拖动状态 const dragStateMap = new WeakMap(); /** * 初始化拖动状态 * @param {HTMLElement} element */ function initDragState(element) { dragStateMap.set(element, { isDragging: false, startX: 0, startY: 0, startLeft: 0, startTop: 0, touchId: null // 用于跟踪多点触控中的特定触点 }); } /** * 处理拖动开始 * @param {HTMLElement} element * @param {Event} e */ function handleDragStart(element, e) { const state = dragStateMap.get(element); if (!state) return; // 阻止默认行为以避免不必要的页面滚动或选择 e.preventDefault(); // 获取初始位置 let clientX, clientY; if (e.type.includes('touch')) { const touch = e.touches[0] || e.changedTouches[0]; clientX = touch.clientX; clientY = touch.clientY; state.touchId = touch.identifier; } else { clientX = e.clientX; clientY = e.clientY; } // 获取元素当前样式 const style = window.getComputedStyle(element); const left = parseFloat(style.left) || 0; const top = parseFloat(style.top) || 0; // 更新状态 state.isDragging = true; state.startX = clientX; state.startY = clientY; state.startLeft = left; state.startTop = top; // 添加拖动类 element.classList.add('dragging'); // 触发自定义事件 const event = new CustomEvent('dragstart', { detail: { x: clientX, y: clientY } }); element.dispatchEvent(event); } /** * 处理拖动移动 * @param {HTMLElement} element * @param {Event} e */ function handleDragMove(element, e) { const state = dragStateMap.get(element); if (!state || !state.isDragging) return; e.preventDefault(); let clientX, clientY; if (e.type.includes('touch')) { // 查找匹配的触点 let touch; if (e.touches) { for (let i = 0; i < e.touches.length; i++) { if (e.touches[i].identifier === state.touchId) { touch = e.touches[i]; break; } } } if (!touch && e.changedTouches) { for (let i = 0; i < e.changedTouches.length; i++) { if (e.changedTouches[i].identifier === state.touchId) { touch = e.changedTouches[i]; break; } } } if (!touch) return; clientX = touch.clientX; clientY = touch.clientY; } else { clientX = e.clientX; clientY = e.clientY; } // 计算新位置 const deltaX = clientX - state.startX; const deltaY = clientY - state.startY; const newLeft = state.startLeft + deltaX; const newTop = state.startTop + deltaY; // 应用新位置 element.style.left = `${newLeft}px`; element.style.top = `${newTop}px`; // 触发自定义事件 const event = new CustomEvent('dragmove', { detail: { x: clientX, y: clientY, left: newLeft, top: newTop } }); element.dispatchEvent(event); } /** * 处理拖动结束 * @param {HTMLElement} element * @param {Event} e */ function handleDragEnd(element, e) { const state = dragStateMap.get(element); if (!state || !state.isDragging) return; e.preventDefault(); state.isDragging = false; element.classList.remove('dragging'); // 触发自定义事件 const event = new CustomEvent('dragend'); element.dispatchEvent(event); } /** * 启用拖动功能 */ HTMLElement.prototype.enableDrag = function() { // 确保元素可以定位 if (window.getComputedStyle(this).position === 'static') { this.style.position = 'relative'; } // 初始化状态 initDragState(this); // 添加事件监听器 this.addEventListener('mousedown', this._dragStartHandler = (e) => handleDragStart(this, e)); this.addEventListener('touchstart', this._dragStartHandlerTouch = (e) => handleDragStart(this, e), { passive: false }); document.addEventListener('mousemove', this._dragMoveHandler = (e) => handleDragMove(this, e)); document.addEventListener('touchmove', this._dragMoveHandlerTouch = (e) => handleDragMove(this, e), { passive: false }); document.addEventListener('mouseup', this._dragEndHandler = (e) => handleDragEnd(this, e)); document.addEventListener('touchend', this._dragEndHandlerTouch = (e) => handleDragEnd(this, e)); document.addEventListener('touchcancel', this._dragEndHandlerTouchCancel = (e) => handleDragEnd(this, e)); }; /** * 禁用拖动功能 */ HTMLElement.prototype.disableDrag = function() { // 移除事件监听器 if (this._dragStartHandler) { this.removeEventListener('mousedown', this._dragStartHandler); this._dragStartHandler = null; } if (this._dragStartHandlerTouch) { this.removeEventListener('touchstart', this._dragStartHandlerTouch); this._dragStartHandlerTouch = null; } if (this._dragMoveHandler) { document.removeEventListener('mousemove', this._dragMoveHandler); this._dragMoveHandler = null; } if (this._dragMoveHandlerTouch) { document.removeEventListener('touchmove', this._dragMoveHandlerTouch); this._dragMoveHandlerTouch = null; } if (this._dragEndHandler) { document.removeEventListener('mouseup', this._dragEndHandler); this._dragEndHandler = null; } if (this._dragEndHandlerTouch) { document.removeEventListener('touchend', this._dragEndHandlerTouch); this._dragEndHandlerTouch = null; } if (this._dragEndHandlerTouchCancel) { document.removeEventListener('touchcancel', this._dragEndHandlerTouchCancel); this._dragEndHandlerTouchCancel = null; } // 移除状态 dragStateMap.delete(this); // 移除拖动类 this.classList.remove('dragging'); }; })();