Article directory
-
- specific goals
- Overall architecture process
- Specific code implementation
-
- Solution 1 How to write hooks
- How to use hooks is as follows
- Option 2: Writing custom instructions
- The method of customizing instructions is as follows:
Specific goals
1. The drag and drop function is fully functional
2. Do not invade business
3. Boundary values cannot be dragged out of the browser.
Overall architecture process
three steps
Mouse press: Record the position when the mouse is pressed and compare it with the position of the upper left corner of the dragged element to calculate the offset of the mouse press point relative to the dragged element.
Mouse movement: Update the position of the dragged element according to the movement of the mouse pointer, ensuring that the element follows the movement of the mouse.
Mouse up: remove event
Specific code implementation
Plan 1 How to write hooks
//Create useDraggable.ts export const useDraggable = (): Ref<HTMLDivElement | null> => {<!-- --> // Declare a ref to store a reference to the div element const divRef = ref<HTMLDivElement | null>(null) // Declare some variables to store mouse or touch position and drag state let offsetX = 0 //The offset of the mouse click or touch point from the left side of the div let offsetY = 0 // The offset of the mouse click or touch point from the top of the div let isDragging = false // Whether dragging is in progress // Function to disable page scrolling const disablePageScroll = () => {<!-- --> document.body.style.overflow = 'hidden' } // Function to enable page scrolling const enablePageScroll = () => {<!-- --> document.body.style.overflow = 'auto' } // Start dragging, disable page scrolling const startDragging = () => {<!-- --> isDragging = true disablePageScroll() } // Stop dragging, enable page scrolling, and later re-enable click events const stopDragging = () => {<!-- --> isDragging = false enablePageScroll() setTimeout(() => {<!-- --> if (divRef.value) {<!-- --> divRef.value.style.pointerEvents = 'auto' } }, 100) } // Handle mouse movement or touch movement events const handleMouseMove = (event: MouseEvent | TouchEvent) => {<!-- --> requestAnimationFrame(() => {<!-- --> if (isDragging & amp; & amp; divRef.value) {<!-- --> const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX const clientY = 'touches' in event ? event.touches[0].clientY : event.clientY const x = clientX - offsetX const y = clientY - offsetY // Prevent event propagation to avoid interfering with normal scrolling event.stopPropagation() event.preventDefault() // Get the maximum visible area width and height of the browser window const maxX = window.innerWidth - (divRef.value.clientWidth || 0) const maxY = window.innerHeight - (divRef.value.clientHeight || 0) //Set the position of the div to ensure it does not exceed the window range divRef.value.style.left = `${<!-- -->Math.min(maxX, Math.max(0, x))}px` divRef.value.style.top = `${<!-- -->Math.min(maxY, Math.max(0, y))}px` // Disable click events on the div to avoid triggering click events when dragging divRef.value.style.pointerEvents = 'none' } }) } //Handle mouse release or touch end event const handleMouseUp = () => {<!-- --> // Stop dragging and resume click events stopDragging() // Remove the listeners for mouse movement events and touch movement events document.removeEventListener('touchmove', handleMouseMove) document.removeEventListener('mousemove', handleMouseMove) } //Handle mouse press or touch start event const handleMouseDown = (event: MouseEvent | TouchEvent) => {<!-- --> if (!divRef.value) return // Get the offset of the mouse click or touch point relative to the left and top of the div offsetX = 'touches' in event ? event.touches[0].clientX - divRef.value.offsetLeft : event.clientX - divRef.value.offsetLeft offsetY = 'touches' in event ? event.touches[0].clientY - divRef.value.offsetTop : event.clientY - divRef.value.offsetTop // Start dragging, add mouse movement and touch movement event listeners startDragging() document.addEventListener('mousemove', handleMouseMove, {<!-- --> passive: false, // Prevent default scrolling behavior }) document.addEventListener('touchmove', handleMouseMove, {<!-- --> passive: false, // Prevent default scrolling behavior }) //Add mouse release and touch end event listeners document.addEventListener('mouseup', handleMouseUp) document.addEventListener('touchend', handleMouseUp) } // When the component is mounted, add mouse press and touch start event listeners onMounted(() => {<!-- --> if (divRef.value) {<!-- --> divRef.value.addEventListener('mousedown', handleMouseDown) divRef.value.addEventListener('touchstart', handleMouseDown) } }) // Remove the event listener when the component is unloaded onUnmounted(() => {<!-- --> if (divRef.value) {<!-- --> divRef.value.removeEventListener('mousedown', handleMouseDown) divRef.value.removeEventListener('touchstart', handleMouseDown) } document.removeEventListener('mouseup', handleMouseUp) document.removeEventListener('touchend', handleMouseUp) }) // Returns a reference to the div element, which can be used in components to create draggable elements. returndivRef }
How to use hooks is as follows
<template> <div ref="draggableDiv" class="it-layout-aside" >Good Good~</div> </template> <script setup lang="tsx"> import {<!-- --> useDraggable } from '~/hooks/useDraggable' const draggableDiv = useDraggable() </script> <style lang="stylus" scoped> .it-layout-aside flexCenter() position fixed bottom 100px right 10px width 60px height 60px border-radius 50% background rgba(0,0,0,.5) Opacity 0.8 color #fff font-size 40px cursor move &:hover opacity 1 </style>
Option 2: How to write custom instructions
const vDraggable = {<!-- --> mounted(el: HTMLElement) {<!-- --> let offsetX = 0 let offsetY = 0 let isDragging = false el.addEventListener('mousedown', event => {<!-- --> isDragging = false offsetX = event.clientX - el.offsetLeft offsetY = event.clientY - el.offsetTop const handleMouseMove = (e: MouseEvent) => {<!-- --> if (!isDragging & amp; & amp; (Math.abs(event.clientX - offsetX) > 5 || Math.abs(event.clientY - offsetY) > 5)) {<!-- --> isDragging = true } if (isDragging) {<!-- --> const x = e.clientX - offsetX const y = e.clientY - offsetY el.style.left = `${<!-- -->Math.min(window.innerWidth - el.clientWidth, Math.max(0, x))}px` el.style.top = `${<!-- -->Math.min(window.innerHeight - el.clientHeight, Math.max(0, y))}px` el.style.pointerEvents = 'none' } } const handleMouseUp = () => {<!-- --> //Set the drag state to false isDragging = false setTimeout(() => {<!-- --> el.style.pointerEvents = 'auto' }, 100) // Remove mouse move and release events document.removeEventListener('mousemove', handleMouseMove) // eslint-disable-next-line @typescript-eslint/no-unused-vars document.removeEventListener('mouseup', handleMouseUp) } }) }, }
The method of customizing instructions is as follows
<template> <div v-draggable class="it-layout-aside" >Are you trendy~</div> </template> <style lang="stylus" scoped> .it-layout-aside flexCenter() position fixed bottom 100px right 10px width 60px height 60px border-radius 50% background rgba(0,0,0,.5) Opacity 0.8 color #fff font-size 40px cursor move &:hover opacity 1 </style>