123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- // 弹窗拖动
- import { ref, Ref, watch, nextTick, computed, reactive } from 'vue';
- type posType = {
- top: number;
- left: number;
- };
- type directionType =
- | 'TOP'
- | 'RIGHT'
- | 'BOTTOM'
- | 'LEFT'
- | 'TOP_RIGHT'
- | 'BOTTOM_RIGHT'
- | 'BOTTOM_LEFT'
- | 'TOP_LEFT';
- type baseSizeType = {
- /**
- * 允许拖动方向 上/上右/右/下右/下/下左/左/上左
- */
- resizeDirection: boolean[];
- layoutTopHeight: number;
- windowHeight: number;
- windowWidth: number;
- // 窗口模式的尺寸
- winWidth: number;
- winHeight: number;
- winMinWidth: number;
- minWidth: number;
- minHeight: number;
- maxHeight: number;
- maxWidth: number;
- transformX: number;
- transformY: number;
- defaultWidth: number;
- defaultHeight: number;
- width: number;
- height: number;
- };
- type initSizeType = {
- /** 默认宽 */
- width?: number;
- /** 默认高 */
- height?: number;
- /** 最小宽 */
- minWidth?: number;
- /** 最小高 */
- minHeight?: number;
- /** 允许拖动方向 上/上右/右/下右/下/下左/左/上左 */
- resizeDirection?: boolean[];
- /** 初始定位 */
- defaultPosition?: string;
- };
- /***
- * 初始化默认弹窗位置
- */
- const initPos = {
- right: 14,
- top: 60
- };
- const getSizeToUnit = (num: number, unit = 'px') => {
- return num > 0 ? num + unit : num + '';
- };
- /**
- * @params classList 可拖动地方的class值,也为唯一值
- * @params boxClass 容器class值必须为唯一值
- * @params dragShow 弹窗是否显示
- * @params initSize 默认尺寸
- */
- export default function useDrag(
- classList: string[],
- boxClass: string,
- dragShow: Ref<boolean>,
- initSize?: initSizeType
- ) {
- const windowInfo = reactive({
- // 小窗口 侧边大窗口
- currentType: 'SMALL' as 'SMALL' | 'LARGE',
- // 弹窗,还是还原
- windowType: 'SMALL' as 'SMALL' | 'LARGE',
- // showScreen: false, // 是否全屏显示
- showType: 'MENU' as 'MENU' | 'CONTENT' // 当前显示哪一部分 - 如果是全屏显示则无效
- });
- const pos = ref<posType>({
- top: -1, // -1 为初始值 代表没有缓存 默认居中
- left: -1
- });
- watch(
- () => windowInfo.windowType,
- () => {
- if (windowInfo.windowType === 'LARGE') {
- baseSize.resizeDirection = [
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true
- ];
- } else if (windowInfo.windowType === 'SMALL') {
- baseSize.resizeDirection = [
- true,
- false,
- false,
- false,
- true,
- false,
- false,
- false
- ];
- }
- const dragDirectionPoints = document.querySelectorAll(
- `.${boxClass} .dragDirectionPoint`
- );
- dragDirectionPoints.forEach((element: any, index) => {
- if (baseSize.resizeDirection[index]) {
- element.style.pointerEvents = 'all';
- } else {
- element.style.pointerEvents = 'none';
- }
- });
- }
- );
- const styleDrag = computed(() => {
- return {
- ...dragStyles,
- width: getSizeToUnit(baseSize.width),
- height: getSizeToUnit(baseSize.height),
- transform: `translate(${baseSize.transformX}px, ${baseSize.transformY}px)`
- };
- });
- const baseSize = reactive<baseSizeType>({
- resizeDirection: initSize?.resizeDirection || [
- true,
- false,
- false,
- false,
- true,
- false,
- false,
- false
- ],
- layoutTopHeight: 0,
- windowHeight: window.innerHeight,
- windowWidth: window.innerWidth,
- // 窗口模式的尺寸
- winWidth: 1010,
- winHeight: 650,
- winMinWidth: initSize?.minWidth || 800,
- minWidth: initSize?.minWidth || 400,
- minHeight: initSize?.minHeight || 340,
- maxHeight: window.innerHeight,
- maxWidth: window.innerWidth > 1024 ? 1024 : window.innerWidth,
- transformX: window.innerWidth - 400 - initPos.right,
- transformY: (window.innerHeight - 640) / 2,
- defaultWidth: initSize?.width || 400,
- defaultHeight: initSize?.height || 640,
- height: initSize?.height || 640,
- width: initSize?.width || 400
- });
- const dragStyles = reactive({
- maxHeight: getSizeToUnit(baseSize.maxHeight),
- minWidth: getSizeToUnit(baseSize.minWidth),
- minHeight: getSizeToUnit(baseSize.minHeight)
- });
- nextTick(() => {
- const layoutTopHeight =
- document.querySelector('.layoutTop')?.clientHeight || 0;
- baseSize.layoutTopHeight = Math.ceil(layoutTopHeight);
- baseSize.windowHeight = window.innerHeight - layoutTopHeight;
- baseSize.maxHeight = window.innerHeight - layoutTopHeight;
- // 判断窗口的高度与默认高度比例
- if (baseSize.defaultHeight >= baseSize.maxHeight) {
- baseSize.defaultHeight = baseSize.maxHeight - 100;
- }
- const translateY = (baseSize.windowHeight - baseSize.defaultHeight) / 2;
- baseSize.transformX =
- baseSize.windowWidth - baseSize.defaultWidth - initPos.right;
- baseSize.transformY = translateY;
- dragStyles.maxHeight = getSizeToUnit(baseSize.maxHeight);
- // 初始化定位
- if (initSize?.defaultPosition === 'center') {
- // alert(initSize.width)
- const transformX = (window.innerWidth - baseSize.defaultWidth) / 2;
- const transformY = (baseSize.windowHeight - baseSize.defaultHeight) / 2;
- baseSize.transformX = transformX;
- baseSize.transformY = transformY;
- }
- const boxClassDom = document.querySelector(`.${boxClass}`) as HTMLElement;
- if (!boxClassDom) {
- return;
- }
- addReSizeDom(boxClassDom, baseSize.resizeDirection);
- classList.map((className: string) => {
- const classDom = document.querySelector(`.${className}`) as HTMLElement;
- if (classDom) {
- classDom.style.cursor = 'move';
- drag(classDom, boxClassDom, baseSize);
- }
- });
- });
- // watch(dragShow, () => {
- // if (dragShow.value) {
- // // 初始化pos值
- // // initPos();
- // window.addEventListener('resize', refreshPos);
- // // nextTick(() => {
- // // const boxClassDom = document.querySelector(
- // // `.${boxClass}`
- // // ) as HTMLElement;
- // // if (!boxClassDom) {
- // // return;
- // // }
- // // console.log(boxClassDom, 'boxClassDom');
- // // classList.map((className: string) => {
- // // const classDom = document.querySelector(
- // // `.${className}`
- // // ) as HTMLElement;
- // // if (classDom) {
- // // classDom.style.cursor = 'move';
- // // drag(classDom, boxClassDom, baseSize);
- // // }
- // // });
- // // });
- // } else {
- // window.removeEventListener('resize', refreshPos);
- // }
- // });
- /**
- * 添加功能放大缩小操作DOM
- * @param parentElement {添加拖动父级元素}
- * @param direction {允许拖动的位置 上/上右/右/下右/下/下左/左/上左}
- */
- function addReSizeDom(parentElement: HTMLElement, direction: boolean[] = []) {
- function addResizeDirection(params: {
- width: string;
- height: string;
- direction: directionType;
- top?: string | any;
- right?: string | any;
- bottom?: string | any;
- left?: string | any;
- cursor: string;
- zIndex?: string;
- pointerEvents: string;
- }) {
- const dom = document.createElement('div');
- dom.className = 'dragDirectionPoint';
- dom.style.position = 'absolute';
- dom.style.userSelect = 'none';
- dom.style.width = params.width;
- dom.style.height = params.height;
- dom.style.left = params.left;
- dom.style.top = params.top;
- dom.style.bottom = params.bottom;
- dom.style.right = params.right;
- dom.style.zIndex = params.zIndex || '9';
- dom.style.cursor = params.cursor;
- dom.style.pointerEvents = params.pointerEvents;
- parentElement.appendChild(dom);
- drag(dom, parentElement, baseSize, 'RESIZE', params.direction);
- }
- // 上
- addResizeDirection({
- width: '100%',
- height: '10px',
- left: '0',
- top: '-5px',
- cursor: 'row-resize',
- direction: 'TOP',
- pointerEvents: direction[0] ? 'all' : 'none'
- });
- // 上右
- addResizeDirection({
- width: '20px',
- height: '20px',
- right: '-10px',
- top: '-10px',
- zIndex: '10',
- cursor: 'ne-resize',
- direction: 'TOP_RIGHT',
- pointerEvents: direction[1] ? 'all' : 'none'
- });
- // 右
- addResizeDirection({
- width: '10px',
- height: '100%',
- top: '0',
- right: '-5px',
- cursor: 'col-resize',
- direction: 'RIGHT',
- pointerEvents: direction[2] ? 'all' : 'none'
- });
- // 下右
- addResizeDirection({
- width: '20px',
- height: '20px',
- right: '-10px',
- bottom: '-10px',
- cursor: 'se-resize',
- zIndex: '10',
- direction: 'BOTTOM_RIGHT',
- pointerEvents: direction[3] ? 'all' : 'none'
- });
- // 下
- addResizeDirection({
- width: '100%',
- height: '10px',
- left: '0',
- bottom: '-5px',
- cursor: 'row-resize',
- direction: 'BOTTOM',
- pointerEvents: direction[4] ? 'all' : 'none'
- });
- // 下左
- addResizeDirection({
- width: '20px',
- height: '20px',
- left: '-10px',
- bottom: '-10px',
- cursor: 'sw-resize',
- zIndex: '10',
- direction: 'BOTTOM_LEFT',
- pointerEvents: direction[5] ? 'all' : 'none'
- });
- // 左
- addResizeDirection({
- width: '10px',
- height: '100%',
- top: '0',
- left: '-5px',
- cursor: 'col-resize',
- direction: 'LEFT',
- pointerEvents: direction[6] ? 'all' : 'none'
- });
- // 上左
- addResizeDirection({
- width: '20px',
- height: '20px',
- left: '-10px',
- top: '-10px',
- cursor: 'nw-resize',
- zIndex: '10',
- direction: 'TOP_LEFT',
- pointerEvents: direction[7] ? 'all' : 'none'
- });
- }
- 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
- // };
- onReset();
- }
- /** 切换窗口 */
- function onScreen() {
- if (windowInfo.windowType === 'SMALL') {
- windowInfo.windowType = 'LARGE';
- baseSize.transformX = (baseSize.windowWidth - baseSize.winWidth) / 2;
- baseSize.transformY =
- (baseSize.windowHeight - baseSize.winHeight) / 2 -
- baseSize.layoutTopHeight / 2;
- baseSize.width = baseSize.winWidth;
- baseSize.height = baseSize.winHeight;
- } else if (windowInfo.windowType === 'LARGE') {
- windowInfo.windowType = 'SMALL';
- const translateY = (baseSize.windowHeight - baseSize.defaultHeight) / 2;
- baseSize.transformX =
- baseSize.windowWidth - baseSize.defaultWidth - initPos.right;
- baseSize.transformY =
- translateY > initPos.top
- ? translateY + (translateY - initPos.top)
- : translateY;
- baseSize.width = baseSize.defaultWidth;
- baseSize.height = baseSize.defaultHeight;
- }
- }
- /** 格式化尺寸 */
- function onResize() {
- windowInfo.windowType = 'SMALL';
- if (windowInfo.currentType === 'SMALL') {
- windowInfo.currentType = 'LARGE';
- baseSize.transformX = baseSize.windowWidth - baseSize.defaultWidth;
- baseSize.transformY = 0;
- baseSize.width = baseSize.defaultWidth;
- baseSize.height = baseSize.maxHeight;
- } else if (windowInfo.currentType === 'LARGE') {
- windowInfo.currentType = 'SMALL';
- baseSize.transformX =
- baseSize.windowWidth - baseSize.defaultWidth - initPos.right;
- baseSize.transformY =
- baseSize.windowHeight - baseSize.defaultHeight - initPos.top;
- baseSize.width = baseSize.defaultWidth;
- baseSize.height = baseSize.defaultHeight;
- }
- }
- /** 重置样式 */
- function onReset() {
- windowInfo.currentType = 'SMALL';
- windowInfo.windowType = 'SMALL';
- if (initSize?.defaultPosition === 'center') {
- const transformX = (window.innerWidth - baseSize.defaultWidth) / 2;
- const transformY = (baseSize.windowHeight - baseSize.defaultHeight) / 2;
- baseSize.transformX = transformX;
- baseSize.transformY = transformY;
- } else {
- baseSize.transformX =
- baseSize.windowWidth - baseSize.defaultWidth - initPos.right;
- baseSize.transformY =
- baseSize.windowHeight - baseSize.defaultHeight - initPos.top;
- }
- baseSize.width = baseSize.defaultWidth;
- baseSize.height = baseSize.defaultHeight;
- }
- return {
- pos,
- baseSize,
- windowInfo,
- styleDrag,
- onScreen,
- onResize,
- onReset
- };
- }
- // 拖动
- function drag(
- el: HTMLElement,
- parentElement: HTMLElement,
- baseSize: baseSizeType,
- type = 'MOVE' as 'MOVE' | 'RESIZE',
- direction?: directionType
- ) {
- function onDown(e: MouseEvent | TouchEvent) {
- const isTouchEv = isTouchEvent(e);
- const event = isTouchEv ? e.touches[0] : e;
- const parentElementRect = parentElement.getBoundingClientRect();
- const downX = event.clientX;
- const downY = event.clientY;
- const clientWidth = document.documentElement.clientWidth;
- const clientHeight = document.documentElement.clientHeight;
- const maxLeft = clientWidth - parentElementRect.width;
- const maxTop =
- clientHeight - parentElementRect.height - baseSize.layoutTopHeight;
- const maxResizeLeft =
- clientWidth -
- baseSize.winMinWidth -
- (clientWidth - parentElementRect.right);
- const maxResizeTop =
- clientHeight - baseSize.minHeight - baseSize.layoutTopHeight;
- const minLeft = 0;
- const minTop = 0;
- const baseHeight = JSON.parse(JSON.stringify(baseSize.height));
- const baseWidth = JSON.parse(JSON.stringify(baseSize.width));
- function onTop(moveY: number) {
- const maxSuffix =
- parentElementRect.bottom -
- baseSize.minHeight -
- baseSize.layoutTopHeight;
- moveY = moveY > maxSuffix ? maxSuffix : moveY;
- const suffix = baseSize.transformY - moveY;
- if (suffix > 0 || baseSize.height > baseSize.minHeight) {
- baseSize.transformY = moveY;
- baseSize.height = baseSize.height + suffix;
- }
- }
- function onRight(moveX: number) {
- const suffix = Math.ceil(
- baseWidth + moveX - (baseSize.width + baseSize.transformX)
- );
- if (suffix > 0 || baseSize.width > baseSize.winMinWidth) {
- baseSize.width =
- baseSize.width + suffix >= baseSize.maxWidth
- ? baseSize.maxWidth
- : baseSize.width + suffix;
- }
- }
- function onBottom(moveY: number) {
- if (baseSize.maxHeight > baseSize.height) {
- const suffix = Math.ceil(
- baseHeight + moveY - (baseSize.height + baseSize.transformY)
- );
- baseSize.height = baseSize.height + suffix;
- }
- }
- function onLeft(moveX: number) {
- moveX =
- moveX < minLeft
- ? minLeft
- : moveX > maxResizeLeft
- ? maxResizeLeft
- : moveX;
- const suffix = baseSize.transformX - moveX;
- if (suffix > 0 || baseSize.width > baseSize.winMinWidth) {
- if (baseSize.width + suffix <= baseSize.maxWidth) {
- baseSize.transformX = moveX;
- baseSize.width = baseSize.width + suffix;
- }
- }
- }
- function onMove(e: MouseEvent | TouchEvent) {
- const event = isTouchEvent(e) ? e.touches[0] : e;
- if (type === 'MOVE') {
- let moveX = parentElementRect.left + (event.clientX - downX);
- let moveY =
- parentElementRect.top -
- baseSize.layoutTopHeight +
- (event.clientY - downY);
- moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
- moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
- // 移动
- baseSize.transformY = moveY;
- baseSize.transformX = moveX;
- } else if (type === 'RESIZE') {
- let moveY =
- parentElementRect.top -
- baseSize.layoutTopHeight +
- (event.clientY - downY);
- moveY =
- moveY < minTop ? minTop : moveY > maxResizeTop ? maxResizeTop : moveY;
- const moveX = parentElementRect.left + (event.clientX - downX);
- // 拖动
- if (direction === 'TOP') {
- onTop(moveY);
- } else if (direction === 'RIGHT') {
- onRight(moveX);
- } else if (direction === 'BOTTOM') {
- onBottom(moveY);
- } else if (direction === 'LEFT') {
- onLeft(moveX);
- } else if (direction === 'TOP_RIGHT') {
- onTop(moveY);
- onRight(moveX);
- } else if (direction === 'BOTTOM_RIGHT') {
- onBottom(moveY);
- onRight(moveX);
- } else if (direction === 'BOTTOM_LEFT') {
- onBottom(moveY);
- onLeft(moveX);
- } else if (direction === 'TOP_LEFT') {
- onTop(moveY);
- onLeft(moveX);
- }
- }
- }
- function onUp() {
- document.removeEventListener(
- isTouchEv ? 'touchmove' : 'mousemove',
- onMove
- );
- document.removeEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
- }
- document.addEventListener(isTouchEv ? 'touchmove' : 'mousemove', onMove);
- document.addEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
- }
- el.addEventListener('mousedown', onDown);
- el.addEventListener('touchstart', onDown);
- }
- function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
- return window.TouchEvent && e instanceof window.TouchEvent;
- }
|