// 弹窗拖动 import { ref, Ref, watch, nextTick, computed } from 'vue'; type posType = { top: number; left: number; }; /** * @params classList 可拖动地方的class值,也为唯一值 * @params boxClass 容器class值必须为唯一值,这个class和useid拼接 作为缓存主键 * @params dragShow 弹窗是否显示 * @params userId 当前用户id */ export default function useDrag( classList: string[], boxClass: string, dragShow: Ref, userId: string ) { const pos = ref({ top: -1, // -1 为初始值 代表没有缓存 默认居中 left: -1 }); const useIdDargClass = userId + boxClass; watch(dragShow, () => { if (dragShow.value) { // 初始化pos值 initPos(); window.addEventListener('resize', refreshPos); nextTick(() => { const boxClassDom = document.querySelector( `.${boxClass}` ) as HTMLElement; if (!boxClassDom) { return; } classList.map((className: string) => { const classDom = document.querySelector( `.${className}` ) as HTMLElement; if (classDom) { classDom.style.cursor = 'move'; drag(classDom, boxClassDom, pos); } }); }); } else { window.removeEventListener('resize', refreshPos); setCachePos(useIdDargClass, pos.value); } }); const styleDrag = computed(() => { // 没有设置拖动的时候保持原本的 return pos.value.left === -1 && pos.value.top === -1 ? {} : { position: 'fixed', left: `${pos.value.left}px`, top: `${pos.value.top}px` }; }); function initPos() { const posCache = getCachePos(useIdDargClass); // 有缓存 用缓存的值,没有缓存用默认 if (posCache) { pos.value = posCache; nextTick(() => { const _itme = setTimeout(() => { clearTimeout(_itme); refreshPos(); }, 300); }); } } function refreshPos() { if (pos.value.left === -1 && pos.value.top === -1) { return; } const boxClassDom = document.querySelector(`.${boxClass}`) as HTMLElement; if (!boxClassDom) return; const parentElementRect = boxClassDom.getBoundingClientRect(); const clientWidth = document.documentElement.clientWidth; const clientHeight = document.documentElement.clientHeight; const { top, left } = pos.value; const maxLeft = clientWidth - parentElementRect.width; const maxTop = clientHeight - parentElementRect.height; let moveX = left; let moveY = top; const minLeft = 0; const minTop = 0; moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX; moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY; pos.value = { top: moveY, left: moveX }; } return { pos, styleDrag }; } // 拖动 function drag(el: HTMLElement, parentElement: HTMLElement, pos: Ref) { function mousedown(e: MouseEvent) { const parentElementRect = parentElement.getBoundingClientRect(); const downX = e.clientX; const downY = e.clientY; const clientWidth = document.documentElement.clientWidth; const clientHeight = document.documentElement.clientHeight; const maxLeft = clientWidth - parentElementRect.width; const maxTop = clientHeight - parentElementRect.height; const minLeft = 0; const minTop = 0; function onMousemove(e: MouseEvent) { let moveX = parentElementRect.left + (e.clientX - downX); let moveY = parentElementRect.top + (e.clientY - downY); moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX; moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY; pos.value = { top: moveY, left: moveX }; } function onMouseup() { document.removeEventListener('mousemove', onMousemove); document.removeEventListener('mouseup', onMouseup); } document.addEventListener('mousemove', onMousemove); document.addEventListener('mouseup', onMouseup); } el.addEventListener('mousedown', mousedown); } // 缓存 const localStorageName = 'dragCachePos'; function getCachePos(useIdDargClass: string): null | undefined | posType { const localCachePos = localStorage.getItem(localStorageName); if (localCachePos) { try { return JSON.parse(localCachePos)[useIdDargClass]; } catch { return null; } } return null; } function setCachePos(useIdDargClass: string, pos: posType) { const localCachePos = localStorage.getItem(localStorageName); let cachePosObj: Record = {}; if (localCachePos) { try { cachePosObj = JSON.parse(localCachePos); } catch { // } } cachePosObj[useIdDargClass] = pos; localStorage.setItem(localStorageName, JSON.stringify(cachePosObj)); }