let seed = 0; const ctx = '@@draggableContext'; let isDialog = false; function handleMousedown(event) { // event.preventDefault(); const el = this; const rect = el.getBoundingClientRect(); Object.assign(el[ctx], { el, type: 'mousedown', rect: rect, x: rect.x || rect.left, y: rect.y || rect.top, dragstartX: event.clientX, // 鼠标按下时坐标 dragstartY: event.clientY, dragendX: void 0, // 鼠标松开时坐标 dragendY: void 0, startX: event.clientX, // 起点坐标 startY: event.clientY, dragging: true, isMove: false, }); callback(el); window.addEventListener('mousemove', el[ctx]._handleMousemove, false); window.addEventListener('mouseup', el[ctx]._handleMouseup, false); } function handleMousemove(el) { return function (event) { if ( el[ctx].binding.modifiers.dialog && event.target.className.indexOf('el-dialog__header') === -1 ) { return; } else { if (event.target === document.documentElement) return; const current = { x: event.clientX, y: event.clientY, }; const diff = { x: current.x - el[ctx].startX, y: current.y - el[ctx].startY, }; if (el[ctx].binding.modifiers.sticky) { // 不会拖出屏幕边缘 const clientWidth = document.documentElement.clientWidth; const clientHeight = document.documentElement.clientHeight; const { x, y, rect: { width, height }, } = el[ctx]; if (diff.x < 0 && x + diff.x <= 0) { el[ctx].x = 0; } else if (diff.x > 0 && x + width - clientWidth >= 0) { el[ctx].x = clientWidth - width; } else { el[ctx].x += diff.x; } if (diff.y < 0 && y + diff.y <= 0) { el[ctx].y = 0; } else if (diff.y > 0 && y + height - clientHeight >= 0) { el[ctx].y = clientHeight - height; } else { el[ctx].y += diff.y; } } else { el[ctx].x += diff.x; el[ctx].y += diff.y; } Object.assign(el[ctx], { el, type: 'mousemove', startX: current.x, startY: current.y, diffX: diff.x, diffY: diff.y, isMove: true, }); callback(el); } // event.preventDefault(); }; } function handleMouseup(el) { return function (event) { // event.preventDefault(); const lastType = el[ctx].type; Object.assign(el[ctx], { el, type: 'mouseup', dragendX: event.clientX, // 鼠标按下时坐标 dragendY: event.clientY, dragging: false, isMove: lastType === 'mousemove', }); callback(el); window.removeEventListener('mousemove', el[ctx]._handleMousemove, false); window.removeEventListener('mouseup', el[ctx]._handleMouseup, false); }; } function callback(el) { const bindingFn = el[ctx]?.binding?.value; if (typeof bindingFn === 'function') { bindingFn({ ...el[ctx], target: el }); } else { const { x, y, rect, dragging } = el[ctx]; if (!dragging) return; el.style.cssText += ` left: ${x}px; top: ${y}px; width: ${rect.width}px; height: ${rect.height}px; `; } } /** * v-draggable * @desc * 1. v-draggable="handleDraggable" 传入回调函数,根据业务逻辑处理 * 2. v-draggable.sticky 限制拖拽范围在屏幕内 * 3. v-draggable.dialog 适配element-ui的dialog * @example * <div v-draggable> * <div v-draggable.sticky> * <div v-draggable.dialog> * <div v-draggable="handleDraggable"> * handleDraggable(config) { * const { type, isMove, dragging } = config; * if (dragging && isMove) { * config.el.style.cssText += ` * left: ${config.x}px; * top: ${config.y}px; * width: ${config.rect.width}px; * height: ${config.rect.height}px; * `; * return; * } * if (type === 'mouseup' && !isMove) { * //业务逻辑 * } * } * ``` */ export default { bind(el, binding, vnode) { const id = seed++; el[ctx] = { id, binding, vnode, _handleMousemove: handleMousemove(el, binding, vnode), _handleMouseup: handleMouseup(el, binding, vnode), }; //适配dialog修饰符 if (el[ctx].binding.modifiers.dialog) { let handler = el.querySelector('.el-dialog__header'); handler.style.cursor = 'move'; } el.addEventListener('mousedown', handleMousedown, false); }, unbind(el) { window.removeEventListener('mousemove', el[ctx]._handleMousemove, false); window.removeEventListener('mouseup', el[ctx]._handleMouseup, false); el.removeEventListener('mousedown', handleMousedown, false); delete el[ctx]; }, }; /** * link:https://huaweicloud.csdn.net/63a5624eb878a54545945c8f.html?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-2-126022408-blog-123231086.235%5Ev38%5Epc_relevant_anti_t3_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-2-126022408-blog-123231086.235%5Ev38%5Epc_relevant_anti_t3_base&utm_relevant_index=3 * */
vue2元素拖拽,适配dialog,支持多修饰符
最新推荐文章于 2024-07-12 11:17:47 发布