当前位置: 首页 > Web前端 > JavaScript

使用React实现鼠标跟随框提示框

时间:2023-03-27 18:13:33 JavaScript

前言鼠标跟随框的功能如下图所示。在前端页面,我们可以为我们后续的鼠标操作提供提示说明,提升用户体验。本文将通过多种方式实现,以满足不同场景的需求。实现原理实现鼠标跟随框的原理很简单,就是监听鼠标在页面上的坐标,然后使用相对定位(position:relative;)、绝对定位(position:absolute;)和fixed定位(position:fixed;)知识。本文使用的是React,不过只要知道原理,技术栈问题不大。如何实现呢,我们往下看。fixed定位的好处是相对于浏览器窗口定位,鼠标跟随框的常见场景是跟随鼠标移动。MousePositionDemo我们先写一个页面介绍鼠标如下框:./MousePositionModal';constMousePositionDemo=()=>{const[visible,setVisible]=useState(false);return({setVisible(true)}}>点击显示{setVisible(false)}}>点击关闭{/*鼠标跟随框*/}

)}exportdefaultMousePositionDemo;index.less.mouse-position-demo{保证金:0自动;高度:500px;宽度:500px;背景色:#fff;padding:24px24px;}MousePositionModal这里我们先通过clientX,clientY返回事件触发时鼠标指针相对于浏览器的页面(或客户区)的横纵坐标,当然,光靠这个可能还不够,我们会发现,当鼠标靠近浏览器页面的最右侧时,鼠标跟随框架的部分页面会被隐藏。为了将鼠标跟随框中的信息完整显示出来,我们需要进行一个简单的计算。当鼠标位置横坐标>鼠标位置横坐标-鼠标选择框的宽度时,让鼠标的横坐标跟随框=鼠标位置横坐标-鼠标选择框的宽度。鼠标跟随随框的具体实现如下:index.tsximportReact,{useState,useEffect}from'react';import'./index.less';interfaceIMousePositionModal{visible:boolean;内容:字符串;defaultPosition:{x:number,y:number}}constMousePositionModal=(props:IMousePositionModal)=>{const{visible,content,defaultPosition}=道具;const[left,setLeft]=useState(defaultPosition.x);const[top,setTop]=useState(defaultPosition.y);useEffect(()=>{if(visible){show();}},[visible]);constshow=()=>{constmodal=document.getElementById('mouse-position-modal');if(modal){document.onmousemove=(event)=>{const{clientX,clientY}=事件||窗口事件;constclientWidth=document.body.clientWidth||文档.documentElement.clientWidth;const{offsetWidth}=模态;让x=clientX+18;consty=客户Y+18;if(x>=clientWidth-offsetWidth){x=clientWidth-offsetWidth;}设置左(x);置顶(y);};}};返回({visible?'visible':'hidden'}`}}>{content}
);};exportdefaultMousePositionModal;这里有两个地方需要注意:一是给鼠标跟随框设置一个固定的位置,二是设置z-index的值要足够大,否则可能会被页面索引上的其他元素覆盖.less.mouse-position-modal{最小宽度:240px;高度:57px;背景:#fff;框阴影:04px12px0rgba(0、0、0、0.15);边界半径:4px;位置:固定;z-指数:2000;填充:8px12px;.mouse-position-modal-content{字体大小:16px;颜色:#262626;}}绝对定位(相对于整个浏览器窗口)使用绝对定位,我们可以达到和上面固定定位类似的效果,但是有一个隐患需要注意。如果靠近鼠标跟随框的父元素使用相对定位,则可能会弄乱鼠标跟随框的实际位置。绝对定位不仅需要考虑可见范围内的位置,还需要考虑浏览器页面的滚动距离。具体实现如下:MousePositionDemo和固定位置一样MousePositionModalindex.tsximportReact,{useState,useEffect}from'react';import'./index.less';interfaceIMousePositionModal{visible:boolean;内容:字符串;defaultPosition:{x:number,y:number}}constMousePositionModal=(props:IMousePositionModal)=>{const{visible,content,defaultPosition}=道具;const[left,setLeft]=useState(defaultPosition.x);const[top,setTop]=useState(defaultPosition.y);useEffect(()=>{if(visible){show();}},[visible]);constshow=()=>{constmodal=document.getElementById('mouse-position-modal');if(modal){document.onmousemove=(event)=>{const{clientX,clientY,pageX,pageY}=事件||窗口事件;常量sl=document.body.scrollLeft||文档.documentElement.scrollLeft;常量st=document.body.scrollTop||文档.documentElement.scrollTop;常量客户宽度=document.body.clientWidth||文档.documentElement.clientWidth;const{offsetWidth}=模态;让x=(pageX||clientX+sl)+18;consty=(pageY||clientY+st)+18;if(x>=clientWidth-offsetWidth){x=clientWidth-offsetWidth;}设置左(x);置顶(y);};}};返回({visible?'visible':'hidden'}`}}>{content}
);};exportdefaultMousePositionModal;index.less.mouse-position-modal{最小宽度:240px;高度:57px;背景:#fff;盒子阴影:04px12px0rgba(0,0,0,0.15);边界半径:4px;位置:绝对;z-指数:2000;填充:8px12px;.mouse-position-modal-content{字体大小:16px;颜色:#262626;}}绝对定位和相对定位(相对于鼠标跟随框的父元素)有时候我们可能不需要整个页面都有鼠标跟随框的提示,在某些情况下只有当鼠标进入页面的某些区域时才会出现提示,如下图:此时需要同时使用绝对定位和相对定位以及offsetX和offsetY。offsetX:指定事件对象与目标节点的padding边缘在X轴方向的偏移量offsetY:指定事件对象与目标节点的padding边缘在Y轴方向的偏移量具体实现位移如下:MousePositionDemoindex.tsximportReact,{useEffect,useState}from'react';import'./index.less';import{Button}from'antd';importMousePositionModal2from'./MousePositionModal2';//兼容使用offsetXconstgetOffsetX=(e:any)=>{constevent=e||窗口事件;常量srcObj=e.target||e.src元素;如果(event.offsetX){返回event.offsetX;}else{constrect=srcObj.getBoundingClientRect();constclientx=event.clientX;返回clientx-rect.left;}}//与offsetY兼容constgetOffsetY=(e:any)=>{constevent=e||窗口事件;常量srcObj=e.target||e.src元素;如果(event.offsetY){返回event.offsetY;}else{constrect=srcObj.getBoundingClientRect();constclientx=event.clientY;返回clientx-rect.top;}}constMousePositionDemo=()=>{const[visible,setVisible]=useState(false);const[defaultPosition,setDefaultPosition]=useState({x:32,y:32})useEffect(()=>{constele=document.getElementById('mouse-position-demo')作为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)}},[])constshow=()=>{setVisible(true)}consthide=()=>{setVisible(false)}constmouseMove=(e:MouseEvent)=>{让x=getOffsetX(e)+18;consty=getOffsetY(e)+18;setDefaultPosition({x,y});}返回()}exportdefaultMousePositionDemo;注意这里的position要设置为relativeindex.less.mouse-position-demo{margin:0auto;高度:500px;宽度:500px;背景色:#fff;填充:24px24px;position:relative;}MousePositionModal2index.tsximportReact,{useState,useEffect}来自'react';import'./index.less';interfaceIMousePositionModal{visible:boolean;内容:字符串;defaultPosition:{x:number,y:number}}constMousePositionModal2=(props:IMousePositionModal)=>{const{visible,content,defaultPosition}=道具;const{x,y}=默认位置;返回({visible?'visible':'hidden'}`}}>{content});};exportdefaultMousePositionModal2;注意要将这里的位置设置为绝对的。index.less.mouse-position-modal{最小宽度:240px;高度:57px;背景:#fff;盒子阴影:04px12px0rgba(0,0,0,0.15);边界半径:4px;位置:绝对;z-指数:2000;填充:8px12px;.mouse-position-modal-content{字体大小:16px;颜色:#262626;三种场景下的三种具体实现方式。如果你有好的实现或者好的建议,欢迎分享~