当前位置: 首页 > 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、盲…...

springsecurity入门登录授权

①我们需要自定义登陆接口&#xff0c;也就是在controller目录新建LoginController类&#xff0c;在controller方法里面去调用service接口&#xff0c;在service接口实现AuthenticationManager去进行用户的认证&#xff0c;注意&#xff0c;我们定义的controller方法要让Spring…...

医学科技查新中对查新点的撰写方法!附案例讲解!

我国的科技查新工作最早是从医学领域开始的&#xff0c;始于1985年中国科学院医学情报所&#xff0c;后来逐步发展到工、农等其 他各个领域。医学科技查新包括立项查新和成果查新两个部分&#xff0c;其中医学立项查新&#xff0c;它是指在医学科研项目申报开题之前&#xff0c…...

2024最新流媒体在线音乐系统网站源码| 音乐社区 | 多语言 | 开心版

2024最新流媒体在线音乐系统网站源码| 音乐社区 | 多语言 | 开心版 https://download.csdn.net/download/huayula/89347742...

回溯算法05(leetcode491/46/47)

参考资料&#xff1a; https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.html 491. 非递减子序列 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素…...

Transformer,革命性的深度学习架构

Transformer 是一种革命性的深度学习架构,专门设计用于处理序列数据,特别是在自然语言处理(NLP)任务中表现卓越。它由 Vaswani 等人在 2017 年发表的论文《Attention is All You Need》中首次提出,打破了当时基于循环神经网络(RNN)和卷积神经网络(CNN)的序列建模常规,…...

实验五:实现循环双链表各种基本运算的算法

实验五&#xff1a;实现循环双链表各种基本运算的算法 一、实验目的与要求 目的:领会循环双链表存储结构和掌握循环双链表中各种基本运算算法设计。 内容:编写一个程序cdinklist.cpp,实现循环双链表的各种基本运算和整体建表算法(假设循环双链表的元素类型ElemType为char),并…...

ElasticSearch IK分词器的安装、词典扩展与停用

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;云原生与服务部署-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 ​编辑 1. 前言 2. IK分词器安装 3. IK分词器词典扩展与停用 4. 总…...

代码随想录训练营总结

为期两个月的代码随想录训练营今天结束了&#xff0c;我想我的收获是非常大的。进到训练营的大群里&#xff0c;令我有种安心的感觉&#xff0c;原来世界各地有这么多与我一起努力的伙伴。更令人安心的是知识星球对于学习进度的规划&#xff0c;细化到每一天每道题&#xff0c;…...

深度学习-转置卷积

转置卷积 转置卷积&#xff08;Transposed Convolution&#xff09;&#xff0c;也被称为反卷积&#xff08;Deconvolution&#xff09;&#xff0c;是深度学习中的一种操作&#xff0c;特别是在卷积神经网络&#xff08;CNN&#xff09;中。它可以将一个低维度的特征图&#x…...

Unity性能优化工具介绍

文章目录 一.Stats组件1.Audio音频的数据组件:2.图形数据 二.Profiler 性能分析器 一.Stats组件 Unity自带Statistics(统计数据),Game视窗中点击Stats打开 1.Audio音频的数据组件: 1):Level 声音强度 单位是分贝(dB) 表示音频听声音的大小,是闪烁波动的. 2):SDPload 数据信…...