您现在的位置是:网站首页> 编程资料编程资料
React实现多个场景下鼠标跟随提示框详解_React_
2023-05-24
423人已围观
简介 React实现多个场景下鼠标跟随提示框详解_React_
前言
鼠标跟随框的作用如下图所示,可以在前端页面上,为我们后续的鼠标操作进行提示说明,提升用户的体验。本文将通过多种方式去实现,从而满足不同场景下的需求。

实现原理
实现鼠标跟随框的原理很简单,就是监听鼠标在页面上的坐标,然后利用相对定位(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 ( {/* 鼠标跟随框 */} ) } 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 ( {content} ); }; 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 ( {content} ); }; 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; } } 绝对定位和相对定位(相对于鼠标跟随框的父元素)
有时候我们可能并不需要在整个页面进行鼠标跟随框的提示,在某些情况下只需要鼠标在进入页面的部分区域才进行提示。
如下图所示:

这个时候就需要同时用到绝对定位和相对定位以及 offsetX 和 offsetY。
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 ( ) } 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 ( {content} ); }; export default MousePositionModal2; 注意要将这里 position 设置为 absolute 。
index.less
本站声明:
1、本站所有资源均来源于互联网,不保证100%完整、不提供任何技术支持;
2、本站所发布的文章以及附件仅限用于学习和研究目的;不得将用于商业或者非法用途;否则由此产生的法律后果,本站概不负责!
相关内容
点击排行
本栏推荐
