当前位置: 首页 > news >正文

js实现鼠标拖拽多选功能

实现功能
在PC端的H5页面中,客户拖动鼠标可以连选多个选项

效果展示
在这里插入图片描述

具体代码如下

<!DOCTYPE html>
<html><head><title>鼠标拖拽多选功能</title><script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script><style type="text/css">* {box-sizing: border-box;}ul {width: 500px;height: auto;margin: 0;padding: 20px;font-size: 0;/*需设置定位*/position: relative;}li {width: 70px;height: 70px;padding: 0;display: inline-block;vertical-align: top;font-size: 13px;border: 1px solid #d9d9d9;}#moveSelected {position: absolute;background-color: blue;opacity: 0.3;border: 1px dashed #d9d9d9;top: 0;left: 0;}.selected {background-color: pink;}</style>
</head><body><ul class="list"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><!-- 鼠标拖拽出的遮罩 (定位为  position:absolute)--><!-- 遮罩最好是在绑定了mouseover事件的元素内部,并且不要阻止遮罩的冒泡事件。这样鼠标移到了遮罩上面,依然可以利用冒泡执行父元素的mouseover事件,就不会出现遮罩只能扩大,不能缩小的情况了(亲自试过) --><div id="moveSelected"></div></ul>
</body></html>
<script type="text/javascript">$(document).ready(function () {let moveSelected = $('#moveSelected')[0];console.log(moveSelected);let flag = false; //是搜开启拖拽的标志let oldLeft = 0; //鼠标按下时的left,toplet oldTop = 0;let selectedList = []; //拖拽多选选中的块集合// 鼠标按下时开启拖拽多选,将遮罩定位并展现$(".list").mousedown(function (event) {flag = true;moveSelected.style.top = event.pageY + 'px';moveSelected.style.left = event.pageX + 'px';oldLeft = event.pageX;oldTop = event.pageY;event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡});// 鼠标移动时计算遮罩的位置,宽 高$(".list").mousemove(function (event) {if (!flag) return; //只有开启了拖拽,才进行mouseover操作if (event.pageX < oldLeft) { //向左拖moveSelected.style.left = event.pageX + 'px';moveSelected.style.width = (oldLeft - event.pageX) + 'px';} else {moveSelected.style.width = (event.pageX - oldLeft) + 'px';}if (event.pageY < oldTop) { //向上moveSelected.style.top = event.pageY + 'px';moveSelected.style.height = (oldTop - event.pageY) + 'px';} else {moveSelected.style.height = (event.pageY - oldTop) + 'px';}event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡});//鼠标抬起时计算遮罩的right 和 bottom,找出遮罩覆盖的块,关闭拖拽选中开关,清除遮罩数据$(".list").mouseup(function (event) {moveSelected.style.bottom = Number(moveSelected.style.top.split('px')[0]) + Number(moveSelected.style.height.split('px')[0]) + 'px';moveSelected.style.right = Number(moveSelected.style.left.split('px')[0]) + Number(moveSelected.style.width.split('px')[0]) + 'px';findSelected();flag = false;clearDragData();event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡});$(".list").mouseleave(function (event) {flag = false;moveSelected.style.width = 0;moveSelected.style.height = 0;moveSelected.style.top = 0;moveSelected.style.left = 0;event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡});function findSelected() {let blockList = $('.list').find('li');for (let i = 0; i < blockList.length; i++) {//计算每个块的定位信息let left = $(blockList[i]).offset().left;let right = $(blockList[i]).width() + left;let top = $(blockList[i]).offset().top;let bottom = $(blockList[i]).height() + top;let leftTwo = moveSelected.style.left.split('px')[0]let rightTwo = moveSelected.style.right.split('px')[0]let topTwo = moveSelected.style.top.split('px')[0]let bottomTwo = moveSelected.style.bottom.split('px')[0]// 判断碰撞if (!(top > bottomTwo || right < leftTwo || bottom < topTwo || left> rightTwo)) {// 碰撞的情况selectedList.push(blockList[i]);$(blockList[i]).addClass('selected');}}console.log(selectedList);}function clearDragData() {moveSelected.style.width = 0;moveSelected.style.height = 0;moveSelected.style.top = 0;moveSelected.style.left = 0;moveSelected.style.bottom = 0;moveSelected.style.right = 0;}});
</script>

考虑方便使用Vue框架的情况,新增一个Vue 3的参考代码,且如果多选时处于已经选择状态也会取消选择

//
// MutiSelectPage
// mrs-console-ui
//
// Created by gaolailong on 2024/05/23.
// Copyright © 2024 上海复微迅捷数字科技股份有限公司. All rights reserved.
//<template><div class="page"><div class="list" @mousedown="handleMouseDown" @mousemove="handleMouseMove" @mouseup="handleMouseUp"@mouseleave="handleMouseLeave"><template v-for="(item, index) in list" :key="index"><div class="can-select-div" :class="item.selected ? 'selected' : ''" :data-index="index">{{ item.text }}</div></template><!-- 鼠标拖拽出的遮罩 (定位为  position:absolute)--><!-- 遮罩最好是在绑定了mouseover事件的元素内部,并且不要阻止遮罩的冒泡事件。这样鼠标移到了遮罩上面,依然可以利用冒泡执行父元素的mouseover事件,就不会出现遮罩只能扩大,不能缩小的情况了(亲自试过) --><div id="moveSelected"></div></div></div>
</template><script lang='ts'>
import { defineComponent, onMounted, reactive } from 'vue'
export default defineComponent({name: 'MutiSelectPage',setup() {let moveSelected: HTMLElement | null = nullonMounted(() => {moveSelected = document.getElementById('moveSelected') as HTMLElement;})const list: Array<Record<string, unknown>> = reactive([])for (let index = 0; index < 10; index++) {const listItem = {text: index,selected: false}list.push(listItem)}let flag = false; //是搜开启拖拽的标志let oldLeft = 0; //鼠标按下时的left,toplet oldTop = 0;const handleMouseDown = (event: any) => {// 处理鼠标按下事件console.log('鼠标按下');if (!moveSelected) return;flag = true;moveSelected.style.top = event.pageY + 'px';moveSelected.style.left = event.pageX + 'px';oldLeft = event.pageX;oldTop = event.pageY;event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡}const handleMouseMove = (event: any) => {// 处理鼠标移动事件的逻辑if (!moveSelected) return;if (!flag) return; //只有开启了拖拽,才进行mouseover操作console.log("鼠标移动了");if (event.pageX < oldLeft) { //向左拖moveSelected.style.left = event.pageX + 'px';moveSelected.style.width = (oldLeft - event.pageX) + 'px';} else {moveSelected.style.width = (event.pageX - oldLeft) + 'px';}if (event.pageY < oldTop) { //向上moveSelected.style.top = event.pageY + 'px';moveSelected.style.height = (oldTop - event.pageY) + 'px';} else {moveSelected.style.height = (event.pageY - oldTop) + 'px';}event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡}const handleMouseUp = (event: any) => {if (!moveSelected) return;// 处理鼠标弹起事件console.log('鼠标弹起');moveSelected.style.bottom = Number(moveSelected.style.top.split('px')[0]) + Number(moveSelected.style.height.split('px')[0]) + 'px';moveSelected.style.right = Number(moveSelected.style.left.split('px')[0]) + Number(moveSelected.style.width.split('px')[0]) + 'px';findSelected();flag = false;clearDragData();event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡}const handleMouseLeave = (event: any) => {console.log('鼠标离开元素');if (!moveSelected) return;flag = false;moveSelected.style.width = '0';moveSelected.style.height = '0';moveSelected.style.top = '0';moveSelected.style.left = '0';event.preventDefault(); // 阻止默认行为event.stopPropagation(); // 阻止事件冒泡}function findSelected() {if (!moveSelected) return;let leftTwo = Number(moveSelected.style.left.split('px')[0])let rightTwo = Number(moveSelected.style.right.split('px')[0])let topTwo = Number(moveSelected.style.top.split('px')[0])let bottomTwo = Number(moveSelected.style.bottom.split('px')[0])// 使用ref获取dom有一个奇怪的现象,手动切换按天/按周时,ref获取到的值不会丢失之前的数据。除非点击外部的“确认查询”按钮。const blockList = document.getElementsByClassName('can-select-div')// console.log(blockList) // 访问DOM元素for (let i = 0; i < blockList.length; i++) {//计算每个块的定位信息let left = (blockList[i] as HTMLDivElement).offsetLeft;let right = (blockList[i] as HTMLDivElement).offsetWidth + left;let top = (blockList[i] as HTMLDivElement).offsetTop;let bottom = (blockList[i] as HTMLDivElement).offsetHeight + top;// 通过比较两个矩形(用 aDiv 和 bDiv 表示)的位置信息来判断它们是否发生碰撞。以下是该碰撞函数的实现思路:// 首先,通过获取 aDiv 和 bDiv 的位置信息,分别计算它们的上边界(t1 和 t2)、右边界(r1 和 r2)、下边界(b1 和 b2)以及左边界(l1 和 l2)。// 接下来,通过比较这些边界信息,判断两个矩形是否发生碰撞。碰撞的情况可以通过以下四个条件中的任意一个来判断:// 如果矩形 aDiv 的上边界大于矩形 bDiv 的下边界,说明 aDiv 在 bDiv 的上方,没有碰撞。// 如果矩形 aDiv 的右边界小于矩形 bDiv 的左边界,说明 aDiv 在 bDiv 的左侧,没有碰撞。// 如果矩形 aDiv 的下边界小于矩形 bDiv 的上边界,说明 aDiv 在 bDiv 的下方,没有碰撞。// 如果矩形 aDiv 的左边界大于矩形 bDiv 的右边界,说明 aDiv 在 bDiv 的右侧,没有碰撞。// 如果上述条件中的任意一个不满足,那么矩形 aDiv 和 bDiv 就发生了碰撞,函数返回 true,否则返回 false 表示没有碰撞。// 判断碰撞if (!(top > bottomTwo || right < leftTwo || bottom < topTwo || left > rightTwo)) {// 碰撞的情况console.log('碰撞了');const itemIndex = (blockList[i] as HTMLDivElement).dataset.indexif (!itemIndex) {return}const item = list[Number(itemIndex)]item.selected = !item.selectedlist.splice(Number(itemIndex), 1, item)}}}const clearDragData = () => {if (!moveSelected) return;moveSelected.style.width = '0';moveSelected.style.height = '0';moveSelected.style.top = '0';moveSelected.style.left = '0';moveSelected.style.bottom = '0';moveSelected.style.right = '0';}return {handleMouseDown,handleMouseMove,handleMouseUp,handleMouseLeave,list,}}
})
</script><style scoped>
.page {box-sizing: border-box;
}.can-select-div {width: 70px;height: 70px;padding: 0;display: inline-block;vertical-align: top;font-size: 13px;border: 1px solid #d9d9d9;
}#moveSelected {position: absolute;background-color: blue;opacity: 0.3;border: 1px dashed #d9d9d9;top: 0;left: 0;
}.selected {background-color: pink;
}
</style>

参考1、参考2

相关文章:

js实现鼠标拖拽多选功能

实现功能 在PC端的H5页面中&#xff0c;客户拖动鼠标可以连选多个选项 效果展示 具体代码如下 <!DOCTYPE html> <html><head><title>鼠标拖拽多选功能</title><script src"https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js&quo…...

postgres_exporter 监控pg坑一:备库无延迟但是监控告警备库延迟

1.问题背景 监控告警某套pg的两个备库延迟大于300s 2.pg备库延迟告警策略 通过postgres_exporter(version 0.13.2)监控生产pg&#xff0c;延迟告警策略如下&#xff1a; pg_replication_lag_seconds{instance!~"host_ip_18801"} > 300 and ON(instance) pg_re…...

vue打包部署到springboot,通过tomcat运行

tomcat默认端口 8080springboot端口 9132vue 端口 9131 框架 项目是基于SpringBootVue前后端分离的仓库管理系统 后端&#xff1a;SpringBoot MybatisPlus前端&#xff1a;Node.js Vue element-ui数据库&#xff1a;mysql 一. 打包Vue项目 cmd中输入命令 npm run build 后…...

如何有效防止数据丢失

在数字时代&#xff0c;数据成为了个人和企业最宝贵的资产之一。不幸的是&#xff0c;数据丢失的威胁无时无刻不在潜伏着&#xff0c;无论是由于技术故障、人为错误还是恶意攻击&#xff0c;都可能对我们的数据造成不可逆转的损失。因此&#xff0c;采取有效的预防措施至关重要…...

linux命令中arj使用

arj 用于创建和管理.arj压缩包 补充说明 arj命令 是 .arj 格式的压缩文件的管理器&#xff0c;用于创建和管理 .arj 压缩包。 语法 arj(参数)参数 操作指令&#xff1a;对 .arj 压缩包执行的操作指令&#xff1b;压缩包名称&#xff1a;指定要操作的arj压缩包名称。 更多…...

UE5中搭建一个简单的海岛

本文将用UE的WaterSystem与地形搭建一个简单的海岛&#xff0c;通过WaterSystem的参数设置&#xff0c;可以更好的自定义海岸线等效果。 1.基础风貌 1.1.首先新建一个Basic基础场景&#xff0c;切换到地形编辑模式刷出一块高地&#xff0c;用于沙滩。 1.2.引入UE官方插件Wat…...

爬虫学习--12.MySQL数据库的基本操作(下)

MySQL查询数据 MySQL 数据库使用SQL SELECT语句来查询数据。 语法&#xff1a;在MySQL数据库中查询数据通用的 SELECT 语法 SELECT 字段1&#xff0c;字段2&#xff0c;……&#xff0c;字段n FROM table_name [WHERE 条件] [LIMIT N] 查询语句中你可以使用一个或者多个表&…...

js的算法-选择排序(简单选择排序)

选择排序 每一趟&#xff08;如第i趟&#xff09;在后面n-i1(i1,2,……n-1)个待排序元素中选取关键字最小的元素&#xff0c;作为有序子序列的第i 个元素&#xff0c;直到第i个元素&#xff0c;直到第n-1趟做完&#xff0c;待排序元素只剩下1个&#xff0c;就不用再选了。 快…...

Mac虚拟机工具 CrossOver 24.0.0 Beta3 Mac中文版

CrossOver是一款在Mac上运行Windows应用程序的软件&#xff0c;无需安装虚拟机或重启计算机&#xff0c;简化了操作过程&#xff0c;提高了工作效率&#xff0c;为用户带来便捷体验。前往Mac青桔下载&#xff0c;享受前所未有的便利和高效。摘要由作者通过智能技术生成 CrossOv…...

路由聚合和VRRP技术

实验拓扑图&#xff1a; 实验需求 1、内网IP地址使用172.16.0.0/16 2、SW1和SW2之间互为备份&#xff1b; 3、VRRP/stp/vlan/eth-trunk均使用&#xff1b; 4、所有pc均通过DHCP获取IP地址&#xff1b; 5、ISP只配置IP地址&#xff1b; 6、所有电脑可以正常访问ISP路由器环…...

【原创教程】三菱FX3U系列培训专题课教案

位置控制三要素 定位控制指令必须要有以下三个条件 1、位置移动速度(电机转速) 2、位置移动距离(电机的旋转圈数) 3、位置移动方向(电机的旋转方向) FX3U_PLC的高速脉冲输出端口 普通输出端口受程序控制,什么时间通,什么时间断,没有固定的通断周期 高速脉冲输出端口…...

清空了电脑回收站,之前的文件还能否恢复?

电脑已成为我们日常生活中不可或缺的一部分。我们在电脑上处理文档、保存图片、下载视频等&#xff0c;而电脑中的回收站则成为我们处理不再需要文件的一个便捷工具&#xff0c;当我们想要删除某些文档的话&#xff0c;它并不是立即从硬盘上消失&#xff0c;而是被系统移动到了…...

设计模式——职责链(责任链)模式

目录 职责链模式 小俱求实习 结构图 实例 职责链模式优点 职责链模式缺点 使用场景 1.springmvc流程 ​2.mybatis的执行流程 3.spring的过滤器和拦截器 职责链模式 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成…...

功耗相关总结

文章目录 功耗相关的使用场景MCU中低功耗的应用RTOS中低功耗应用 功耗相关的使用场景 目前越来越多的嵌入式设备采用电池进行供电&#xff0c;而不是跟台式电脑一样&#xff0c;可以一直连接着电源。在电池供电的场景下&#xff0c;对功耗的要求很高&#xff0c;工程师们尽量希…...

17款奔驰GLS450升级头等舱行政独立四座马鞍是什么样体验

五座版本&#xff1a;迈巴赫GLS480的五座版本通常指的是具有五个座位的配置&#xff0c;包括两个前排座椅和三个后排座椅。这种配置适合搭载更多乘客&#xff0c;后排座椅通常为三人座设计&#xff0c;乘坐人数较多。 四座版本&#xff1a;迈巴赫GLS480的四座版本通常指的是具…...

浏览器的下载行为基本原理

浏览器解析 在使用浏览器访问某些资源时&#xff0c;有些资源是直接下载有些资源是直接打开。例如前端的html&#xff0c;xml&#xff0c;css&#xff0c;图片等资源都是直接打开&#xff0c;而txt&#xff0c;excel等文件是直接下载。那么如何控制访问一个资源时是下载文件还…...

浅谈微服务的自动化部署

一、常用部署工具 jenkins,docker生态是比较常用的工具&#xff0c;本文也主要是聊这几个。其他如Kubernetes (K8s)&#xff0c;Ansible&#xff0c;GitLab CI/CD等工具本文只是暂时提一下&#xff0c;不展开讨论。 二、比较jenkins和docker生态 1、jenkins 优点 jenkins功…...

【C语言】8.C语言操作符详解(1)

文章目录 1.操作符的分类2.⼆进制和进制转换3.原码、反码、补码4.移位操作符4.1 左移操作符4.2 右移操作符 5.位操作符&#xff1a;&、|、^、~5.1 &&#xff1a;按位与5.2 |&#xff1a;按位或5.3 ^&#xff1a;按位异或5.4 ~&#xff1a;按位取反5.5 例题例题1例题2例…...

Buzz库网络爬虫实例:快速爬取百度搜索实时热点

前言 随着互联网的发展&#xff0c;信息获取已经成为了人们日常生活和工作中的重要一环。而在信息获取的过程中&#xff0c;网络爬虫作为一种自动化的数据采集工具&#xff0c;为我们提供了极大的便利。本文将介绍如何利用PHP编写一个简单而高效的网络爬虫&#xff0c;实现快速…...

SQL注入:pikachu靶场中的SQL注入通关

目录 1、数字型注入&#xff08;post&#xff09; 2、字符型注入&#xff08;get&#xff09; 3、搜索型注入 4、XX型注入 5、"insert/update"注入 Insert&#xff1a; update&#xff1a; 6、"delete"注入 7、"http header"注入 8、盲…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献

Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译&#xff1a; ### 胃肠道癌症的发病率呈上升趋势&#xff0c;且有年轻化倾向&#xff08;Bray等人&#xff0c;2018&#x…...

RushDB开源程序 是现代应用程序和 AI 的即时数据库。建立在 Neo4j 之上

一、软件介绍 文末提供程序和源码下载 RushDB 改变了您处理图形数据的方式 — 不需要 Schema&#xff0c;不需要复杂的查询&#xff0c;只需推送数据即可。 二、Key Features ✨ 主要特点 Instant Setup: Be productive in seconds, not days 即时设置 &#xff1a;在几秒钟…...

MySQL基本操作(续)

第3章&#xff1a;MySQL基本操作&#xff08;续&#xff09; 3.3 表操作 表是关系型数据库中存储数据的基本结构&#xff0c;由行和列组成。在MySQL中&#xff0c;表操作包括创建表、查看表结构、修改表和删除表等。本节将详细介绍这些操作。 3.3.1 创建表 在MySQL中&#…...