Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aDragModalHook:useDragModal #5501

Open
pinecone-squirrel opened this issue Dec 22, 2023 · 6 comments · May be fixed by #6583
Open

aDragModalHook:useDragModal #5501

pinecone-squirrel opened this issue Dec 22, 2023 · 6 comments · May be fixed by #6583
Labels

Comments

@pinecone-squirrel
Copy link

This function solves the problem (这个功能解决的问题)

Realization of modal drag

Expected API (期望的 API)

useDragModal

@github-actions github-actions bot added the feature request New feature or request label Dec 22, 2023
@pinecone-squirrel
Copy link
Author

`/**
*模态框拖动Hook

  • @param {HTMLElement} draggableEl - 要拖动的元素。
  • @param {string} [childrenSelectors='.n-card-header'] - 用于查找要应用拖动事件的子元素的选择器。
    */
    export const useDragModal = (draggableEl, childrenSelectors = '.n-card-header') => {
    const targetEl = draggableEl.querySelector(childrenSelectors)
    targetEl.style.cursor = 'move'
    mousedown(targetEl, draggableEl)
    mouseleave(targetEl)
    mouseup(targetEl)
    }
    const mousedown = (targetEl, draggableEl) => {
    targetEl.onmousedown = event => {
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight
    const { width, height, x: minMoveX, y: minMoveY } = draggableEl.getBoundingClientRect()
    const maxMoveX = viewportWidth - width - minMoveX
    const maxMoveY = viewportHeight - height - minMoveY
    const { clientX: originX, clientY: originY } = event
    let { left, top } = draggableEl.style
    // getComputedStyle
    const styleLeft = left?.replace('px', '') ?? 0
    const styleTop = top.replace('px', '') ?? 0
    document.onmousemove = e => {
    const { clientX, clientY } = e
    let moveX = clientX - originX
    let moveY = clientY - originY
    if (moveX > maxMoveX) {
    moveX = maxMoveX
    } else if (-moveX > minMoveX) {
    moveX = -minMoveX
    }
    if (moveY > maxMoveY) {
    moveY = maxMoveY
    } else if (-moveY > minMoveY) {
    moveY = -minMoveY
    }
    draggableEl.style.cssText += ;left:${+styleLeft + moveX}px;top:${+styleTop + moveY}px;
    }
    }
    }
    const mouseup = () => {
    document.onmouseup = () => {
    document.onmousemove = null
    }
    }
    const mouseleave = targetEl => {
    targetEl.onmouseleave = () => (document.onmousemove = null)
    }
    `

I should have implemented it, but his closing animation is less than perfect

Usage
image

@OrbisK
Copy link
Collaborator

OrbisK commented Jan 8, 2024

is you request like #5554 ?

@pinecone-squirrel
Copy link
Author

is you request like #5554 ?

yes

But I've already done that.

But I hope the officials will support it

@liuyang0826
Copy link
Contributor

liuyang0826 commented Jan 12, 2024

export interface Options {
  /**
   * 禁用拖拽的类名
   * @default drag-disabled
   */
  disabledClass?: string
  /**
   * 最大搜索深度
   * @default 3
   */
  maxDepth?: number
}

export function modalDraggable(options?: Options) {
  const { disabledClass = 'drag-disabled', maxDepth = 3 } = options ?? {}

  const findModalHeader = (target: HTMLElement) => {
    let depth = 0

    while (target && depth < maxDepth) {
      if (target.classList.contains('n-card-header__close')) return

      if (target.classList.contains('n-card-header') && target.parentElement?.classList.contains('n-modal')) {
        if (target.parentElement?.classList.contains(disabledClass)) return

        return target
      }

      target = target.parentElement as HTMLElement
      depth += 1
    }
  }

  const handleMousedown = (originEvent: MouseEvent) => {
    const header = findModalHeader(originEvent.target as HTMLElement)
    if (!header) return
    const targetEl = header.parentElement as HTMLElement

    const { innerWidth, innerHeight } = window
    const userSelect = document.body.style.userSelect
    document.body.style.userSelect = 'none'

    const originLeft = parseFloat(targetEl.style.left) || 0
    const originTop = parseFloat(targetEl.style.top) || 0

    const handleMousemove = (moveEvent: MouseEvent) => {
      const left = originLeft + Math.min(innerWidth, Math.max(0, moveEvent.clientX)) - originEvent.clientX
      const top = originTop + Math.min(innerHeight, Math.max(0, moveEvent.clientY)) - originEvent.clientY
      targetEl.style.left = `${left}px`
      targetEl.style.top = `${top}px`
    }

    const handleMouseup = () => {
      document.body.style.userSelect = userSelect
      document.removeEventListener('mousemove', handleMousemove)
      document.removeEventListener('mouseup', handleMouseup)
    }

    document.addEventListener('mousemove', handleMousemove)
    document.addEventListener('mouseup', handleMouseup)
  }

  document.addEventListener('mousedown', handleMousedown)

  return () => document.removeEventListener('mousedown', handleMousedown)
}

我目前的做法,把这个方法在main.js里面执行一下,所有的modal都可以拖动,需要禁止的地方加drag-disabled类名

@fxjs
Copy link

fxjs commented Mar 7, 2024

`/** *模态框拖动Hook

  • @param {HTMLElement} draggableEl - 要拖动的元素。
  • @param {string} [childrenSelectors='.n-card-header'] - 用于查找要应用拖动事件的子元素的选择器。
    */
    export const useDragModal = (draggableEl, childrenSelectors = '.n-card-header') => {
    const targetEl = draggableEl.querySelector(childrenSelectors)
    targetEl.style.cursor = 'move'
    mousedown(targetEl, draggableEl)
    mouseleave(targetEl)
    mouseup(targetEl)
    }
    const mousedown = (targetEl, draggableEl) => {
    targetEl.onmousedown = event => {
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight
    const { width, height, x: minMoveX, y: minMoveY } = draggableEl.getBoundingClientRect()
    const maxMoveX = viewportWidth - width - minMoveX
    const maxMoveY = viewportHeight - height - minMoveY
    const { clientX: originX, clientY: originY } = event
    let { left, top } = draggableEl.style
    // getComputedStyle
    const styleLeft = left?.replace('px', '') ?? 0
    const styleTop = top.replace('px', '') ?? 0
    document.onmousemove = e => {
    const { clientX, clientY } = e
    let moveX = clientX - originX
    let moveY = clientY - originY
    if (moveX > maxMoveX) {
    moveX = maxMoveX
    } else if (-moveX > minMoveX) {
    moveX = -minMoveX
    }
    if (moveY > maxMoveY) {
    moveY = maxMoveY
    } else if (-moveY > minMoveY) {
    moveY = -minMoveY
    }
    draggableEl.style.cssText += ;left:${+styleLeft + moveX}px;top:${+styleTop + moveY}px;
    }
    }
    }
    const mouseup = () => {
    document.onmouseup = () => {
    document.onmousemove = null
    }
    }
    const mouseleave = targetEl => {
    targetEl.onmouseleave = () => (document.onmousemove = null)
    }
    `

I should have implemented it, but his closing animation is less than perfect

Usage image


优化鼠标移出标题后窗口不跟随问题:

export const useDragModal = (draggableEl: HTMLElement, childrenSelectors = '.n-card-header') => {
  const targetEl = draggableEl.querySelector(childrenSelectors) as HTMLElement;
  if (!targetEl) {
    return;
  }
  targetEl.style.cursor = 'move';
  targetEl.style.userSelect = 'none';
  mousedown(targetEl as HTMLElement, draggableEl);
  mouseup();
};

const mousedown = (targetEl: HTMLElement, draggableEl: HTMLElement) => {
  targetEl.onmousedown = (event: MouseEvent) => {
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
    const { width, height, x: minMoveX, y: minMoveY } = draggableEl.getBoundingClientRect();
    const maxMoveX = viewportWidth - width - minMoveX;
    const maxMoveY = viewportHeight - height - minMoveY;
    const { clientX: originX, clientY: originY } = event;
    const { left, top } = draggableEl.style;
    const styleLeft = left?.replace('px', '') ?? 0;
    const styleTop = top.replace('px', '') ?? 0;

    document.onmousemove = (e: MouseEvent) => {
      const { clientX, clientY } = e;
      let moveX = clientX - originX;
      let moveY = clientY - originY;
      if (moveX > maxMoveX) {
        moveX = maxMoveX;
      } else if (-moveX > minMoveX) {
        moveX = -minMoveX;
      }
      if (moveY > maxMoveY) {
        moveY = maxMoveY;
      } else if (-moveY > minMoveY) {
        moveY = -minMoveY;
      }
      draggableEl.style.cssText += `;left:${+styleLeft + moveX}px;top:${+styleTop + moveY}px`;
    };
  };
};

const mouseup = () => {
  document.onmouseup = () => {
    document.onmousemove = null;
  };
};

@pinecone-squirrel
Copy link
Author

`/** *模态框拖动Hook

  • @param {HTMLElement} draggableEl - 要拖动的元素。
  • @param {string} [childrenSelectors='.n-card-header'] - 用于查找要应用拖动事件的子元素的选择器。
    */
    export const useDragModal = (draggableEl, childrenSelectors = '.n-card-header') => {
    const targetEl = draggableEl.querySelector(childrenSelectors)
    targetEl.style.cursor = 'move'
    mousedown(targetEl, draggableEl)
    mouseleave(targetEl)
    mouseup(targetEl)
    }
    const mousedown = (targetEl, draggableEl) => {
    targetEl.onmousedown = event => {
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight
    const { width, height, x: minMoveX, y: minMoveY } = draggableEl.getBoundingClientRect()
    const maxMoveX = viewportWidth - width - minMoveX
    const maxMoveY = viewportHeight - height - minMoveY
    const { clientX: originX, clientY: originY } = event
    let { left, top } = draggableEl.style
    // getComputedStyle
    const styleLeft = left?.replace('px', '') ?? 0
    const styleTop = top.replace('px', '') ?? 0
    document.onmousemove = e => {
    const { clientX, clientY } = e
    let moveX = clientX - originX
    let moveY = clientY - originY
    if (moveX > maxMoveX) {
    moveX = maxMoveX
    } else if (-moveX > minMoveX) {
    moveX = -minMoveX
    }
    if (moveY > maxMoveY) {
    moveY = maxMoveY
    } else if (-moveY > minMoveY) {
    moveY = -minMoveY
    }
    draggableEl.style.cssText += ;left:${+styleLeft + moveX}px;top:${+styleTop + moveY}px;
    }
    }
    }
    const mouseup = () => {
    document.onmouseup = () => {
    document.onmousemove = null
    }
    }
    const mouseleave = targetEl => {
    targetEl.onmouseleave = () => (document.onmousemove = null)
    }
    `

I should have implemented it, but his closing animation is less than perfect
Usage image

优化鼠标移出标题后窗口不跟随问题:

export const useDragModal = (draggableEl: HTMLElement, childrenSelectors = '.n-card-header') => {
  const targetEl = draggableEl.querySelector(childrenSelectors) as HTMLElement;
  if (!targetEl) {
    return;
  }
  targetEl.style.cursor = 'move';
  targetEl.style.userSelect = 'none';
  mousedown(targetEl as HTMLElement, draggableEl);
  mouseup();
};

const mousedown = (targetEl: HTMLElement, draggableEl: HTMLElement) => {
  targetEl.onmousedown = (event: MouseEvent) => {
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
    const { width, height, x: minMoveX, y: minMoveY } = draggableEl.getBoundingClientRect();
    const maxMoveX = viewportWidth - width - minMoveX;
    const maxMoveY = viewportHeight - height - minMoveY;
    const { clientX: originX, clientY: originY } = event;
    const { left, top } = draggableEl.style;
    const styleLeft = left?.replace('px', '') ?? 0;
    const styleTop = top.replace('px', '') ?? 0;

    document.onmousemove = (e: MouseEvent) => {
      const { clientX, clientY } = e;
      let moveX = clientX - originX;
      let moveY = clientY - originY;
      if (moveX > maxMoveX) {
        moveX = maxMoveX;
      } else if (-moveX > minMoveX) {
        moveX = -minMoveX;
      }
      if (moveY > maxMoveY) {
        moveY = maxMoveY;
      } else if (-moveY > minMoveY) {
        moveY = -minMoveY;
      }
      draggableEl.style.cssText += `;left:${+styleLeft + moveX}px;top:${+styleTop + moveY}px`;
    };
  };
};

const mouseup = () => {
  document.onmouseup = () => {
    document.onmousemove = null;
  };
};

我特意让鼠标移出就拖动不了的,哈哈哈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants