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

利用React实现多个场景下的鼠标跟随框提示框

前言

鼠标跟随框的作用如下图所示,可以在前端页面上,为我们后续的鼠标操作进行提示说明,提升用户的体验。本文将通过多种方式去实现,从而满足不同场景下的需求。

鼠标跟随框1.gif

实现原理

实现鼠标跟随框的原理很简单,就是监听鼠标在页面上的坐标,然后利用相对定位(position: relative;)、绝对定位(position: absolute;)和固定定位(position: fixed;)等相关知识。

本文是利用的 React,但只要知道原理,技术栈什么的问题都不大。具体怎么实现,咱接着往下看。

固定定位实现

固定定位的好处是,相对于浏览器窗口定位,而鼠标跟随框的通用场景就是跟随鼠标移动。

MousePositionDemo

我们先写一个页面,用来引入鼠标跟随框:

index.tsx

import React, { useEffect, useState  } from 'react';
import './index.less';
import { Button } from 'antd';
import MousePositionModal from './MousePositionModal';const MousePositionDemo = () => {const [visible, setVisible] = useState(false);return (<div id="mouse-position-demo" className="mouse-position-demo"><Button onClick={() => {setVisible(true)}}>点击显示</Button><Button onClick={() => {setVisible(false)}}>点击关闭</Button>{/* 鼠标跟随框 */}<MousePositionModalvisible={visible}content="鼠标跟随"defaultPosition={{x: 32,y: 32}}/></div>)
}export default MousePositionDemo;

index.less

.mouse-position-demo {margin: 0 auto;height: 500px;width: 500px;background-color: #fff;padding: 24px 24px;
}

MousePositionModal

这里我们首先通过 clientX, clientY 来返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平和垂直坐标。

当然,仅这样可能是不够的,我们会发现在鼠标靠近浏览器页面最右侧的时候,鼠标跟随框的部分页面会被隐藏掉。为了能够完整的展示鼠标跟随框中的信息,我们需要进行一个简单的计算,当 鼠标位置的横坐标 > 鼠标位置横坐标 - 鼠标选择框的宽度 时,就让 鼠标跟随框的横坐标 = 鼠标位置横坐标 - 鼠标选择框的宽度

鼠标跟随框的具体实现如下:

index.tsx

import React, { useState, useEffect } from 'react';
import './index.less';interface IMousePositionModal {visible: boolean;content: string;defaultPosition: {x: number,y: number}
}const MousePositionModal = (props: IMousePositionModal) => {const { visible, content, defaultPosition } = props;const [left, setLeft] = useState(defaultPosition.x);const [top, setTop] = useState(defaultPosition.y);useEffect(() => {if (visible) {show();}}, [visible]);const show = () => {const modal = document.getElementById('mouse-position-modal');if (modal) {document.onmousemove = (event) => {const { clientX, clientY } = event || window.event;const clientWidth = document.body.clientWidth || document.documentElement.clientWidth;const { offsetWidth } = modal;let x = clientX + 18;const y = clientY + 18;if (x >= clientWidth - offsetWidth) {x = clientWidth - offsetWidth;}setLeft(x);setTop(y);};}};return (<divid="mouse-position-modal"className="mouse-position-modal"style={{ left: `${left}px`, top: `${top}px`, visibility: `${visible ? 'visible' : 'hidden'}`}}><div className="mouse-position-modal-content">{content}</div></div>);
};export default MousePositionModal;

这里有两个地点需要注意:一是给鼠标跟随框设置固定定位,二是要将 z-index 的值设置的足够大,不然有可能会被页面上的其他元素遮住。

index.less

.mouse-position-modal {min-width: 240px;height: 57px;background: #fff;box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);border-radius: 4px;position: fixed;z-index: 2000;padding: 8px 12px;.mouse-position-modal-content {font-size: 16px;color: #262626;}
}

绝对定位(相对于整个浏览器窗口)

利用绝对定位我们可以实现和上面固定定位相似的效果,但是有个隐患需要注意,如果鼠标跟随框的某个相近的父元素用了相对定位,那鼠标跟随框的实际位置就可能会乱套了。

绝对定位不仅要考虑可视范围内的位置,还需要考虑浏览器页面滚动的距离。

具体实现如下:

MousePositionDemo

和固定定位一样

MousePositionModal

index.tsx

import React, { useState, useEffect } from 'react';
import './index.less';interface IMousePositionModal {visible: boolean;content: string;defaultPosition: {x: number,y: number}
}const MousePositionModal = (props: IMousePositionModal) => {const { visible, content, defaultPosition } = props;const [left, setLeft] = useState(defaultPosition.x);const [top, setTop] = useState(defaultPosition.y);useEffect(() => {if (visible) {show();}}, [visible]);const show = () => {const modal = document.getElementById('mouse-position-modal');if (modal) {document.onmousemove = (event) => {const { clientX, clientY, pageX, pageY } = event || window.event;const sl = document.body.scrollLeft || document.documentElement.scrollLeft;const st = document.body.scrollTop || document.documentElement.scrollTop;const clientWidth = document.body.clientWidth || document.documentElement.clientWidth;const { offsetWidth } = modal;let x = (pageX || clientX + sl) + 18;const y = (pageY || clientY + st) + 18;if (x >= clientWidth - offsetWidth) {x = clientWidth - offsetWidth;}setLeft(x);setTop(y);};}};return (<divid="mouse-position-modal"className="mouse-position-modal"style={{ left: `${left}px`, top: `${top}px`, visibility: `${visible ? 'visible' : 'hidden'}`}}><div className="mouse-position-modal-content">{content}</div></div>);
};export default MousePositionModal;

index.less

.mouse-position-modal {min-width: 240px;height: 57px;background: #fff;box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);border-radius: 4px;position: absolute;z-index: 2000;padding: 8px 12px;.mouse-position-modal-content {font-size: 16px;color: #262626;}
}

绝对定位和相对定位(相对于鼠标跟随框的父元素)

有时候我们可能并不需要在整个页面进行鼠标跟随框的提示,在某些情况下只需要鼠标在进入页面的部分区域才进行提示。

如下图所示:

鼠标跟随框2.gif

这个时候就需要同时用到绝对定位和相对定位以及 offsetXoffsetY

offsetX: 规定了事件对象与目标节点的内填充边(padding edge)在 X 轴方向上的偏移量
offsetY: 规定了事件对象与目标节点的内填充边(padding edge)在 Y 轴方向上的偏移量

具体实现如下:

MousePositionDemo

index.tsx

import React, { useEffect, useState  } from 'react';
import './index.less';
import { Button } from 'antd';
import MousePositionModal2 from './MousePositionModal2';// 兼容offsetX
const getOffsetX = (e: any) =>{const event = e || window.event;const srcObj = e.target || e.srcElement;if (event.offsetX){return event.offsetX;}else{const rect = srcObj.getBoundingClientRect();const clientx = event.clientX;return clientx - rect.left;}
}// 兼容offsetY
const getOffsetY = (e: any) => {const event = e || window.event;const srcObj = e.target || e.srcElement;if (event.offsetY){return event.offsetY;}else{const rect = srcObj.getBoundingClientRect();const clientx = event.clientY;return clientx - rect.top;}
}const MousePositionDemo = () => {const [visible, setVisible] = useState(false);const [defaultPosition, setDefaultPosition] = useState({x: 32,y: 32})useEffect(() => {const ele = document.getElementById('mouse-position-demo') as HTMLElement;ele.addEventListener('mouseenter', show)ele.addEventListener('mousemove', mouseMove)ele.addEventListener('mouseleave', hide)return () => {ele.removeEventListener('mouseenter', show)ele.removeEventListener('mousemove', mouseMove)ele.removeEventListener('mouseleave', hide)}}, [])const show = () => {setVisible(true)}const hide = () => {setVisible(false)}const mouseMove = (e: MouseEvent) => {let x = getOffsetX(e) + 18;const y = getOffsetY(e) + 18;setDefaultPosition({ x, y });}return (<div id="mouse-position-demo" className="mouse-position-demo"><MousePositionModal2visible={visible}content="鼠标跟随"defaultPosition={defaultPosition}/></div>)
}export default MousePositionDemo;

注意要将这里 position 设置为 relative

index.less

.mouse-position-demo {margin: 0 auto;height: 500px;width: 500px;background-color: #fff;padding: 24px 24px;position: relative;
}

MousePositionModal2

index.tsx

import React, { useState, useEffect } from 'react';
import './index.less';interface IMousePositionModal {visible: boolean;content: string;defaultPosition: {x: number,y: number}
}const MousePositionModal2 = (props: IMousePositionModal) => {const { visible, content, defaultPosition } = props;const { x, y } = defaultPosition;return (<divid="mouse-position-modal"className="mouse-position-modal"style={{ left: `${x}px`, top: `${y}px`, visibility: `${visible ? 'visible' : 'hidden'}` }}><div className="mouse-position-modal-content">{content}</div></div>);
};export default MousePositionModal2;

注意要将这里 position 设置为 absolute 。

index.less

.mouse-position-modal {min-width: 240px;height: 57px;background: #fff;box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.15);border-radius: 4px;position: absolute;z-index: 2000;padding: 8px 12px;.mouse-position-modal-content {font-size: 16px;color: #262626;}
}

最后

本文结合实例,详细的介绍了鼠标跟随框在三种场景下的三种具体实现的方法。如果大家有好的实现方式或者好的建议,欢迎提出来一起交流~

相关文章:

利用React实现多个场景下的鼠标跟随框提示框

前言 鼠标跟随框的作用如下图所示&#xff0c;可以在前端页面上&#xff0c;为我们后续的鼠标操作进行提示说明&#xff0c;提升用户的体验。本文将通过多种方式去实现&#xff0c;从而满足不同场景下的需求。 实现原理 实现鼠标跟随框的原理很简单&#xff0c;就是监听鼠标在…...

【安全知识】——如何绕过cdn获取真实ip

作者名&#xff1a;白昼安全主页面链接&#xff1a; 主页传送门创作初心&#xff1a; 以后赚大钱座右铭&#xff1a; 不要让时代的悲哀成为你的悲哀专研方向&#xff1a; web安全&#xff0c;后渗透技术每日鸡汤&#xff1a; 现在的样子是你想要的吗&#xff1f;cdn简单来说就是…...

JavaScript内存泄露和垃圾回收机制

1、是什么&#xff1f;内存泄露&#xff08;Memory leak&#xff09;是在计算机科学中&#xff0c;由于疏忽或错误造成程序未能释放已经不再使用的内存。并非指内存在物理上的消失&#xff0c;而是应用程序分配某段内存后&#xff0c;由于设计错误&#xff0c;导致在释放该段内…...

Kubernetes02:知识图谱

Kubernetes01&#xff1a;知识图谱 MESOS APACHE 分布式资源管理框架 2019-5 Twitter 》 Kubernetes Docker Swarm 2019-07 阿里云宣布 Docker Swarm 剔除 Kubernetes Google 10年容器化基础架构 borg Go语言 Borg 特点 轻量级&#xff1a;消耗资源小 开源 弹性伸缩 负载均…...

nginx-服务器banner泄漏风险

http { server_tokens off; # 隐藏Nginx版本号 .... }...

GCC 同名符号冲突解决办法

一、绪论 作为 C/C 的开发者&#xff0c;大多数都会清楚课本上动态库以及静态库的优缺点&#xff0c;在教科书上谈及到动态库的一个优点是可以节约磁盘和内存的空间&#xff0c;多个可执行程序通过动态库加载的方式共用一段代码段 &#xff1b;而时至今日&#xff0c;再看看上…...

下一代视频编码技术2023

下一代视频编码技术 下面将从这两个角度来介绍华为云视频在下一代视频编码技术上的一些工作。这些技术得益于华为2012 媒体技术院全力支持。 2.1 下一代视频编码标准技术 从上图可以看出&#xff0c;下一代的视频编码标准大概分为三个阵营或者三个类型&#xff1a; 国际标准…...

最新最全中小微企业研究数据:海量创业公司信息与获取投资信息(1985-2021年)

一、企业获取投资名单&资方信息 数据来源&#xff1a;搜企网、企查查、天眼查 时间跨度&#xff1a;1985年8月-2021年9月 区域范围&#xff1a;全国范围 数据字段&#xff1a;企业名称、时间、获得投资金额以及投资方信息 部分数据&#xff1a; DateCompany_nameUnit…...

springboot数据源浅析

DataSourceAutoConfiguration分析 SpringBoot有一个自动配置DataSourceAutoConfiguration 为数据源配置 /META-INF/spring.factories文件找到DataSourceAutoConfiguration配置类 一、先来看下DataSourceAutoConfiguration配置类生效的时机&#xff0c;观察源码发现 Configura…...

2022黑马Redis跟学笔记.实战篇(七)

2022黑马Redis跟学笔记.实战篇 七4.11.附近的店铺功能4.11.1. GEO数据结构的基本用法1. 附近商户-导入店铺数据到GEO4.11.2. 获取附近的店铺1. 附近商户-实现附近商户功能4.9. 签到功能4.9.1.BitMap原理1. 用户签到-BitMap功能演示4.9.2.实现签到功能4.9.3.实现补签功能4.9.4.统…...

QT mp3音乐播放器实现框架,Qt鼠标事件,网络编程,QSqlite,Json解析,HTTP请求等

QT mp3音乐播放器实现框架&#xff0c;Qt鼠标事件&#xff0c;网络编程&#xff0c;QSqlite,Json解析&#xff0c;HTTP请求等框架搭建UI设计mp3.hmp3.cpp隐藏窗口标题 最大化 最小化 关闭框架搭建 .pro添加 # 网络 添加多媒体 数据库 QT network multimedia sql添加头…...

硬件学习 软件Cadence day04 PCB 封装绘制

1.文章内容&#xff1a; 1. 贴片式电容 PCB 封装绘制 &#xff08;型号 c0603 &#xff09; 2. 贴片式电阻 PCB 封装绘制 &#xff08;型号 r0603 &#xff09; 3. 安规式电容 PCB 封装绘制 &#xff08;这个就是 有一个电容&#xff0c;插入一个搞好的孔里面 …...

【Java】yield()和join()区别

一、java 线程调度的背景 java虚拟机要求在多线程中实现 preemptive和priority-based调度&#xff0c;这意味着java中每一个线程被分配了特定的优先级&#xff0c;正整数在定义好的范围内不断减。优先级可以通过开发者改变但是java虚拟机从不改变线程的优先级&#xff0c;即使…...

【MySQL】Java连接MySQL数据库(封装版只需会MySQL)

一、准备普通项目如果创建的是普通的Java项目&#xff0c;我们需要去maven仓库下载jdbc驱动包然导入项目中就能使用&#xff0c;具体步骤详见MySQL数据库之Java中如何使用数据库【JDBC编程】maven项目如果创建的项目是maven项目&#xff0c;我们只需在pom.xml文件里引入一组依赖…...

【java基础】运算符

运算符 operator 运算符优先级 Operators 操作员Precedence 优先级postfix 后缀expr expr--unary 一元的expr --expr expr -expr ~ !multiplicative 〔数〕乘法的 / %additive 添加剂 -shift 移动<< >> >>>relational 关系的< > < > insta…...

带噪学习-概述

在实际应用的时候&#xff0c;我们的样本不会是完全干净的&#xff0c;即存在噪声样本。那使用存在噪声的样本时&#xff0c;我们如何更有效的进行模型学习呢&#xff1f;Label Dependent Nose样本选择&#xff08;Sample Selection&#xff09;第一种很直接的想法&#xff0c;…...

Scratch少儿编程案例-多彩打地鼠

专栏分享 点击跳转=>Unity3D特效百例点击跳转=>案例项目实战源码点击跳转=>游戏脚本-辅助自动化点击跳转=>Android控件全解手册点击跳转=>Scratch编程案例👉关于作者...

为什么拔掉计算机网线还能ping通127.0.0.1?

前言 当我们在计算机上拔掉网线之后&#xff0c;发现我们仍然可以使用ping命令来ping通本机的IP地址127.0.0.1&#xff0c;这让很多人感到困惑&#xff0c;认为拔掉网线后计算机就无法与外界通信了&#xff0c;为什么还能ping通本机的IP地址呢&#xff1f; 本文的目的是通过对…...

Android kotlin 内、外部存储根目录及测试(可以实现仿微信未读消息数提示数字)

<<返回总目录 文章目录 一、内部存储与外部存储三、外部存储的写读测试(可以实现仿微信未读消息数提示数字)一、内部存储与外部存储 所有Android设备都有两个文件存储区域:内部存储空间(internal Storage)和外部存储空间(external Storage)。所以,Android系统从逻…...

Android 7.0 OTA升级(高通)

文章目录1. Full OTA 方式升级介绍1.1 Full OTA 制作第一步&#xff1a;生成 msm89xx-target_files-eng.XXX.zip1.2 Full OTA 制作第二步&#xff1a;Modem 等非 HLOS 加入升级包的方法1.3 Full OTA 制作第三步&#xff1a;生成 update.zip 升级包2. Incremental OTA 方式升级介…...

工作负载之DeployMent

DeployMent 无状态工作负载&#xff08;Deployment&#xff09;&#xff1a;即kubernetes中的“Deployment”&#xff0c;无状态工作负载支持弹性伸缩与滚动升级&#xff0c;适用于实例完全独立、功能相同的场景&#xff0c;如&#xff1a;nginx、wordpress等。 也是公司中应…...

淘宝tmall页面数据获取,API接口对接程序

item_get-获得淘宝商品详情请求参数请求参数&#xff1a;num_iid652874751412&is_promotion1参数说明&#xff1a;num_iid:淘宝商品IDis_promotion:是否获取取促销价响应参数Version: Date:2022-04-04名称类型必须示例值描述itemitem[]1宝贝详情数据num_iidBigint152081325…...

基于粒子群优化算法的电动汽车充放电V2G研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

java并发编程原理2 (AQS, ReentrantLock,线程池)

一、AQS&#xff1a; 1.1 AQS是什么&#xff1f; AQS就是一个抽象队列同步器&#xff0c;abstract queued sychronizer&#xff0c;本质就是一个抽象类。 AQS中有一个核心属性state&#xff0c;其次还有一个双向链表以及一个单项链表。 首先state是基于volatile修饰&#x…...

研报精选230219

目录 【行业230219山西证券】煤炭行业周报&#xff1a;复工改善&#xff0c;港口价格企稳反弹【行业230219中航证券】农林牧渔行业周观点&#xff1a;一号文件落地&#xff0c;生物育种超势不改【行业230219华西证券】汽车行业周报&#xff1a;新车密集上市 自主转型提速【个股…...

【PPPoE】PPPoE拨号流程

简介 PPPoE&#xff08;Point-to-Point Protocol over Ethernet&#xff09;是一种在以太网上封装PPP协议的方式&#xff0c;常用于在宽带接入中进行拨号。 PPPoE的拨号原理如下&#xff1a; 客户端发起PPPoE Active Discovery Initiation (PADI)报文&#xff0c;广播到网络…...

django项目实战(django+bootstrap实现增删改查)

目录 一、创建django项目 二、修改默认配置 三、配置数据库连接 四、创建表结构 五、在app当中创建静态文件 六、页面实战-部门管理 1、实现一个部门列表页面 2、实现新增部门页面 3、实现删除部门 4、实现部门编辑功能 七、模版的继承 1、创建模板layout.html 1&…...

Lesson4---Python语言基础(2)

4.1 内置数据结构 4.1.1 序列数据结构&#xff08;sequence&#xff09; 成员是有序排列的每个元素的位置称为下标或索引通过索引访问序列中的成员Python中的序列数据类型有字符串、列表、元组 “abc” ≠ “bac” 4.1.1.1 创建列表和元组 Python中的列表和元组&#xff0c…...

NCHW - NHWC - CHWN 排列

TensorFlow有两种数据格式NHWC和NCHW,默认的数据格式是NHWC,可以通过参数data_format指定数据格式。这个参数规定了 input Tensor 和 output Tensor 的排列方式。 1、data_format 设置为 “NHWC” 时,排列顺序为 [batch, height, width, channels] 设置为 “NCHW” 时,排…...

2019蓝桥杯真题矩阵切割(填空题) C语言/C++

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 小明有一些矩形的材料&#xff0c;他要从这些矩形材料中切割出一些正方形。 当他面对一块矩形材料时&#xff0c;他总是从中间切割一刀&#xff0c;切出一块最大的正…...

wordpress下载最新版本/天津疫情最新情况

➊平列复合句 平行复合句&#xff0c;即两个以上同等性质的分句依次排列&#xff0c;之间无任何语法标志相连&#xff0c;共同构成的一个概念完整的组句。它又被称为la partage或lhypotaxe&#xff08;平行句&#xff09; ⒶJe lai vu, jai veng mon honneur et mon pre ;je le…...

酉阳网站建设/软文大全800字

在运行程序的时候&#xff0c;我们一般可以进行run configuration的配置&#xff0c;就比如tomcat源码导入eclipse之后&#xff0c;我们可以发现其运行配置如下&#xff1a; 其中Program arguments配置的元素就是我们传入main方法的字符串数组&#xff0c;而VM arguments其实就…...

网站上的视频直播是怎么做的呢/企业查询平台

前言 近几年来&#xff0c;互联网行业变化非常大&#xff0c;除了龙头企业的更替&#xff0c;“裁员潮”“失业潮”也不断掀起&#xff0c;尤其是对于年纪太大的程序员真的是不太友好。但是&#xff0c;根据数据统计表明&#xff0c;自2018来&#xff0c;学习IT行业的人不减反…...

为什么浙江建设厅网站/如何提高百度搜索排名

http://www.blogjava.net/sean/archive/2005/10/26/16929.html先放在这里了&#xff0c;鬼知道我什么时候才有空看:-)这是一组系列文章&#xff0c;主题是轻量级的开发&#xff0c;内容涵盖了轻量级容器、敏捷开发、持久化策略、以及Java语言本身的局限&#xff0c;等等等等。英…...

wordpress编辑分类/旅游最新资讯 新闻

欢迎转载&#xff0c;转载请注明&#xff1a;本文出自Bin的专栏blog.csdn.net/xbinworld。 技术交流QQ群&#xff1a;433250724&#xff0c;欢迎对算法、技术、应用感兴趣的同学加入。 最近在复习经典机器学习算法的同时&#xff0c;也仔细看了一些深度学习的典型算法。深度学…...

建设营销型网站的步骤/青岛网站关键词优化公司

列表的创建&#xff1a; 基本语法【】创建&#xff1a; list&#xff08;&#xff09;创建&#xff1a; 将任何可迭代的数据转化成列表 例子&#xff1a; Python3中range&#xff08;&#xff09;返回的是一个range对象&#xff0c;而不是列表我们需要通过list()的方法将其转…...