【Web系列二十七】Vue实现dom元素拖拽并限制移动范围

目录

需求

拖拽功能封装

使用拖拽功能

vite-env.d.ts

main.ts

test.vue


需求

dom元素拖拽并限制在父组件范围内

拖拽功能封装

javascript 复制代码
export const initVDrag = (vue) => {
	vue.directive('drag', (el) => {
		const oDiv = el // 当前元素
		oDiv.onmousedown = (e) => {
			let target = oDiv
			while (
				window.getComputedStyle(target).position !== 'absolute' &&
				target !== document.body
			) {
				target = target.parentElement
			}
			let parent = target.parentNode
			
			document.onselectstart = () => {
				return false
			}
			if (!target.getAttribute('init_x')) {
				target.setAttribute('init_x', target.offsetLeft)
				target.setAttribute('init_y', target.offsetTop)
			}
			
			// e.clientX, e.clientY是鼠标点击的位置
			// target.offsetLeft, target.offsetTop是当前元素左上角的位置
			// 计算鼠标按下的位置距离当前元素左上角的距离
			const disX = e.clientX - target.offsetLeft
			const disY = e.clientY - target.offsetTop
			// target.clientWidth, target.clientHeight是当前元素的尺寸
			// parent.clientWidth, parent.clientHeight是父元素的尺寸
			// parent.offsetLeft, parent.offsetTop是父元素左上角的位置
			// 可移动范围的位置
			const minX = parent.offsetLeft
			const maxX = parent.offsetLeft + parent.clientWidth - target.clientWidth
			const minY = parent.offsetTop
			const maxY = parent.offsetTop + parent.clientHeight - target.clientHeight
			
			document.onmousemove = (e) => {
				// 通过事件委托,计算移动的距离,e是最新的鼠标位置,disX、disY是鼠标刚点击时的位置
				let l = e.clientX - disX
				let t = e.clientY - disY
				
				// 约束移动范围在父元素区域内
				if (l < minX) {
					l = minX
				} else if (l > maxX) {
					l = maxX
				}
				if (t < minY) {
					t = minY
				} else if (t > maxY) {
					t = maxY
				}
				
				// 给当前元素样式中的left和top赋值
				target.style.left = l + 'px'
				target.style.top = t + 'px'
			}
			
			document.onmouseup = (e) => {
				document.onmousemove = null
				document.onmouseup = null
				document.onselectstart = null
			}
			
			// 不return false的话,可能导致鼠标黏连,鼠标粘在dom上拿不下来,相当于onmouseup失效
			return false
		}
	})
}

使用拖拽功能

以vite为例:

vite-env.d.ts

TypeScript 复制代码
...
declare module '@utils/directive/vDrag.js'
...

main.ts

TypeScript 复制代码
...
import { createApp } from 'vue'
import { initVDrag } from '@/utils/directive/vDrag.js'
...
let instance: any = null
instance = createApp(App)
initVDrag(instance)
...

test.vue

html 复制代码
<template>
    <div v-drag />
</template>
相关推荐
程序员清洒1 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季6662 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
天人合一peng2 小时前
Unity中button 和toggle监听事件函数有无参数
前端·unity·游戏引擎
会飞的战斗鸡2 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling3 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
毕设源码-朱学姐3 小时前
【开题答辩全过程】以 基于web教师继续教育系统的设计与实现为例,包含答辩的问题和答案
前端
qq_177767373 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767373 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
web打印社区3 小时前
web-print-pdf:突破浏览器限制,实现专业级Web静默打印
前端·javascript·vue.js·electron·html
RFCEO4 小时前
前端编程 课程十三、:CSS核心基础1:CSS选择器
前端·css·css基础选择器详细教程·css类选择器使用方法·css类选择器命名规范·css后代选择器·精准选中嵌套元素