mousedown拖拽功能(vue3+ts)
因为项目有rem适配,使用第三方插件无法处理适配问题,所有只能自己写拖拽功能了
拖拽一般都会想到按下,移动,放开,但是本人亲测,就在div绑定一个按下事件就行了(在事件里面写另外两个事件),另外两个绑上,会莫名其妙卡死,那种莫名其妙的问题
推荐几个开发调试时使用的第三方拖动插件吧,虽然没用上,但是他们是真的好vue-drag-resize和vuedraggable,其中前者更轻量化,后者功能更全
主要功能:
效果图:

界面:(就是大的父盒子包着几个小盒子,盒子里面有图片和文字)
<div class="range" id="range" ref="range"><divclass="iconItem"v-for="(item, index) in pointList":key="index"@mousedown.stop.prevent.native="mousedown($event, item)":style="{left: item.dx + 'px',top: item.dy + 'px','z-index': item.zIndex,}"><!--@mousemove.stop.prevent.native="mousemove($event, item)"@mouseup.stop.prevent.native="mouseup($event, item)"--><imgdraggable="false":src="typeList[item.type].src":alt="typeList[item.type].name + item.EName"/><span>{{ typeList[item.type].name + item.EName }}</span></div></div>
逻辑:
<script setup lang="ts">
import { ref, reactive, watch, computed, Ref } from "vue";
import { mapPunctuation } from "@/utils/youran";
let rem = ref(0.005208); // 10/1920 做好功能给上面的left top乘上去就行了 left: item.dx * rem + 'px'const range: Ref = ref(null);// 这里只是把存在文件里的base64图片文件取出来,
let typeList = reactive([{type: 1,src: "",name: "球机-摄像头",},{type: 2,src: "",name: "抢机-摄像头",},{type: 3,src: "",name: "无源打卡设备",},{type: 4,src: "",name: "无源打卡设备",},{type: 5,src: "",name: "反向控制",},
]);typeList.forEach((item, index) => {item.src = mapPunctuation[index].src;
});let pointList = ref([{fId: "111",type: 1,EId: "",EName: "",dx: 0,dy: 0,zIndex: 2,},
]);// 鼠标事件
let downType = ref(false);
let disX = 0;
let disY = 0;
let odiv: any = null;
let mousedown = (e: any, item: any) => {downType.value = true;console.log("按下事件");odiv = e.target;disX = e.clientX - odiv.offsetLeft;disY = e.clientY - odiv.offsetTop;document.onmousemove = (e) => {console.log("移动事件");//计算元素位置(需要判断临界值)let left = e.clientX - disX;let top = e.clientY - disY;let { offsetHeight: pondModelHeight, offsetWidth: pondModelWidth } =range.value;let { offsetHeight: sonNodeHeight, offsetWidth: sonNodeWidth } = odiv;// 左上角(left)if (left < 0) {left = 0;}if (top < 0) {top = 0;}// 左下角if (top > pondModelHeight - sonNodeHeight) {top = pondModelHeight - sonNodeHeight;}if (left > pondModelWidth - sonNodeWidth) {left = pondModelWidth - sonNodeWidth;}item.dx = left;item.dy = top;item.zIndex = 999;};document.onmouseup = (e) => {console.log("放开事件");document.onmousemove = null;document.onmouseup = null;item.zIndex = 1;odiv = null;};
};
</script>
css:本来不该放出来,但是我在这里踩坑了,觉得其他人也会(img图片有默认的拖拽,很难禁止,所以拿一个伪元素直接放在img上面,不给点img就不会踩坑)
.range {width: 960px;height: 540px;background-color: pink;position: relative;.iconItem {position: absolute;left: 10px;top: 10px;z-index: 2;display: flex;align-items: center;cursor: move;user-select: none;width: 32px;height: 32px;background: yellow;img {width: 32px;height: 32px;}// 关键&::before {content: " ";width: 100%;height: 100%;position: absolute;top: 0;left: 0;z-index: 3;}&:hover {// span {// display: block;// }}span {display: none;font-size: 12px;font-family: YouSheBiaoTiHei;color: red;}}}
完整代码:(建议按照上面的一点点复制吧,有几个文件是外部的base64图片)
<template><div class="PastureMap"><div class="mapContent"><div class="mapBox"><div class="range" id="range" ref="range"><divclass="iconItem"v-for="(item, index) in pointList":key="index"@mousedown.stop.prevent.native="mousedown($event, item)":style="{left: item.dx + 'px',top: item.dy + 'px','z-index': item.zIndex,}"><!--@mousemove.stop.prevent.native="mousemove($event, item)"@mouseup.stop.prevent.native="mouseup($event, item)"--><imgdraggable="false":src="typeList[item.type].src":alt="typeList[item.type].name + item.EName"/><span>{{ typeList[item.type].name + item.EName }}</span></div></div></div><div class="operationPanel"><div class="addIConCard"><div class="title"><span>新增图标</span></div><div class="box"><div class="bgImg"><div class="left"><span>背景图:</span></div><div class="right"><button>选择图片</button><span>建议尺寸:960*540</span></div></div><div class="iconBtnForm"><div class="cell"><div class="left"><span>圈舍</span></div><div class="right"><input type="text" placeholder="请选择圈舍" /></div></div><div class="cell"><div class="left"><span>设备编号</span></div><div class="right"><input type="text" placeholder="请输入设备编号" /></div></div><div class="cell"><div class="left"><span>类型</span></div><div class="right"><input type="text" placeholder="请选择类型" /></div></div></div><div class="addBtn"><button>新增</button></div></div></div><div class="iconList"><div class="item" v-for="(item, index) in pointList" :key="index"><div class="left"><span>类型</span></div><div class="right"><input type="text" placeholder="名称" /></div><div class="del"><img src="" alt="del" /></div></div></div></div></div></div>
</template><script setup lang="ts">
import { ref, reactive, watch, computed, Ref } from "vue";
import { mapPunctuation } from "@/utils/youran";
let rem = ref(0.005208); // 10/1920const range: Ref = ref(null);
let typeList = reactive([{type: 1,src: "",name: "球机-摄像头",},{type: 2,src: "",name: "抢机-摄像头",},{type: 3,src: "",name: "无源打卡设备",},{type: 4,src: "",name: "无源打卡设备",},{type: 5,src: "",name: "反向控制",},
]);typeList.forEach((item, index) => {item.src = mapPunctuation[index].src;
});let pointList = ref([{fId: "111",type: 1,EId: "",EName: "",dx: 0,dy: 0,zIndex: 2,},
]);// 鼠标事件
let downType = ref(false);
let disX = 0;
let disY = 0;
let odiv: any = null;
let mousedown = (e: any, item: any) => {downType.value = true;console.log("按下事件");odiv = e.target;disX = e.clientX - odiv.offsetLeft;disY = e.clientY - odiv.offsetTop;document.onmousemove = (e) => {console.log("移动事件");//计算元素位置(需要判断临界值)let left = e.clientX - disX;let top = e.clientY - disY;let { offsetHeight: pondModelHeight, offsetWidth: pondModelWidth } =range.value;let { offsetHeight: sonNodeHeight, offsetWidth: sonNodeWidth } = odiv;// 左上角(left)if (left < 0) {left = 0;}if (top < 0) {top = 0;}// 左下角if (top > pondModelHeight - sonNodeHeight) {top = pondModelHeight - sonNodeHeight;}if (left > pondModelWidth - sonNodeWidth) {left = pondModelWidth - sonNodeWidth;}item.dx = left;item.dy = top;item.zIndex = 999;};document.onmouseup = (e) => {console.log("放开事件");document.onmousemove = null;document.onmouseup = null;item.zIndex = 1;odiv = null;};
};
</script><style lang="less" scoped>
.PastureMap {height: 100%;.mapContent {display: flex;height: 100%;.mapBox {flex: 1;height: 100%;.range {width: 960px;height: 540px;background-color: pink;position: relative;.iconItem {position: absolute;left: 10px;top: 10px;z-index: 2;display: flex;align-items: center;cursor: move;user-select: none;width: 32px;height: 32px;background: yellow;img {width: 32px;height: 32px;}&::before {content: " ";width: 100%;height: 100%;position: absolute;top: 0;left: 0;z-index: 3;}&:hover {// span {// display: block;// }}span {display: none;font-size: 12px;font-family: YouSheBiaoTiHei;color: red;}}}}.operationPanel {width: 270px;.addIConCard {.title {span {}}.box {.bgImg {display: flex;align-items: center;.left {}.right {}}.iconBtnForm {.cell {display: flex;align-items: center;.left {span {}}.right {input {}}}}}}.iconList {.item {display: flex;align-items: center;position: relative;.left {span {}}.right {input {}}.del {position: absolute;top: 0;right: 0;}}}}}
}
</style>相关文章:
mousedown拖拽功能(vue3+ts)
因为项目有rem适配,使用第三方插件无法处理适配问题,所有只能自己写拖拽功能了 拖拽一般都会想到按下,移动,放开,但是本人亲测,就在div绑定一个按下事件就行了(在事件里面写另外两个事件&#x…...
【论文阅读】基于深度学习的时序异常检测——TransAD
系列文章链接 数据基础:多维时序数据集简介 论文一:2022 Anomaly Transformer:异常分数预测 论文二:2022 TransAD:异常分数预测 论文链接:TransAD.pdf 代码库链接:https://github.com/imperial…...
NLPCC 出版部分相关源码记录
目录 Download Unzip Author Title Affiliation Check number of tex Zip Rename Delete Download import requests from bs4 import BeautifulSoup# 登录网站并获取登录后的 session def login(username, password):login_url https://example.com/loginsession re…...
【Windbg】通过网络调试windows内核
环境 windows版本:win10_x64 1901 windbg版本:1.2306.12001.0 HOST 1、windbg软件设置。 点击菜单文件,然后如下图操作。 2、等待连接。 ************* Waiting for Debugger Extensions Gallery to Initialize **************>>&…...
代码随想录算法训练营之JAVA|第二十四天| 93. 复原 IP 地址
今天是第24天刷leetcode,立个flag,打卡60天。 算法挑战链接 93. 复原 IP 地址https://leetcode.cn/problems/restore-ip-addresses/ 第一想法 题目理解:将一串数字字符串变成正确的ip格式的字符串。 这类题目是切分字符串,ip一…...
网络安全 Day30-运维安全项目-堡垒机部署
运维安全项目-堡垒机部署 1. 运维安全项目-架构概述2. 运维安全项目之堡垒机2.1 堡垒机概述2.2 堡垒机选型2.3 环境准备2.4 部署Teleport堡垒机2.4.1 下载与部署2.4.2 启动2.4.3 浏览器访问teleport2.4.4 进行配置2.4.5 安装teleport客户端 2.5 teleport连接服务器 1. 运维安全…...
电脑文件夹备份命令
电脑文件夹备份 cmd窗口输入shell:startup 将备份.bat文件放到,自启动文件夹下 bat文件内容写以下就可以了 Xcopy "D:\文件\" "F:\文件备份\" /E/H/C/I/y...
RocketMQ Learning(一)
目录 一、RocketMQ 0、RocketMQ的产品发展 1、RocketMQ安装 1.1、windows下的安装 注意事项 1.2、Linux下的安装 1.3、源码的安装 1.4、控制台 2、消息发送方式 2.1、发送同步消息 2.2、发送异步消息 2.3、单向发送 3、消息消费方式 3.1、负载均衡模式࿰…...
libmpv使用滤镜处理视频进行播放
一、前言 作为一个功能强大的多媒体框架,libmpv为开发者提供了广泛的功能和灵活的控制权。滤镜是libmpv的一个重要特性,允许开发者对视频进行各种实时处理和增强,从而满足用户对于个性化、创意化和高质量视频体验的需求。 滤镜是一种在视频渲染过程中应用特定效果的技术。…...
Harbor.cfg 配置文件参数详解
目录 Harbor.cfg 配置文件参数详解 所需参数: hostname: ui_url_protocol: max_job_workers: db_password: customize_crt: ssl_cert: ssl_cert_key: secretkey_path&#…...
模仿火星科技 基于cesium+ 贴地测量+可编辑
当您进入Cesium的编辑贴地测量世界,下面是一个详细的操作过程,帮助您顺利使用这些功能: 1. 创建提示窗: 启动Cesium应用,地图场景将打开,欢迎您进入编辑模式。在屏幕的一角,一个友好的提示窗将…...
模仿火星科技 基于cesium+角度测量+高度测量+可编辑
1. 创建提示窗: 启动Cesium应用,地图场景将打开,欢迎您进入编辑模式。 在屏幕的一角,一个友好的提示窗将呈现,随着您的操作,它会为您提供有用的信息和指导。 2. 绘制面积: 轻轻点击鼠标左键&a…...
Codeforces の 动态规划
Codeforces Round 785 (Div. 2) - C. Palindrome Basis dp(9/100) 题目链接 思路:整数划分基础上加一个判断回文的条件 整数划分思路:背包容量为n,物品有体积为1~n n种,每种无数个,求使背包恰好装满的方案数——完全背…...
数学建模-爬虫系统学习
尚硅谷Python爬虫教程小白零基础速通(含python基础爬虫案例) 内容包括:Python基础、Urllib、解析(xpath、jsonpath、beautiful)、requests、selenium、Scrapy框架 python基础 进阶(字符串 列表 元组 字典…...
HarmonyOS/OpenHarmony应用开发-ArkTS语言渲染控制概述
ArkUI通过自定义组件的build()函数和builder装饰器中的声明式UI描述语句构建相应的UI。 在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染控制语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件渲染语句,基于数组数…...
【力扣刷题 | 第二十五天】
目录 前言: 474. 一和零 - 力扣(LeetCode) 总结: 前言: 今天我们依旧暴打动态规划 474. 一和零 - 力扣(LeetCode) 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集…...
GO学习之 函数(Function)
GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 文章目录 GO系列前言一、什么是…...
Jstack线上问题排查
1.top查找出哪个进程消耗的cpu高。执行top命令,默认是进程视图,其中PID是进程号(记下进程号) 2.top中shifth 或“H”查找出哪个线程消耗的cpu高 (记下最高的几个线程号) jstack 进程号 >> pid-cpu.…...
VIM 编辑器: Bram Moolenaar
VIM 用了很长时间, 个人的 VIM 配置文件差不多10年没有更新了。以前写程序的时候, 编辑都用这个。 linux kernel, boost规模的代码都不在话下。现在虽然代码写的少了,依然是我打开文件的首选。 现在用手机了,配个蓝牙键…...
鸿蒙应用开发指南:从零开始构建一款智能音乐播放器
介绍 随着鸿蒙操作系统的发布,开发者们迫不及待地想要探索鸿蒙应用的开发。本篇博客将以构建一款智能音乐播放器为例,带你一步步了解鸿蒙应用开发的技术要点和实践。我们将使用HarmonyOS的开发环境和MarkDown进行排版,方便你快速上手。 准备…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
