您现在的位置是:网站首页> 编程资料编程资料

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; } } 

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

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

如下图所示:

这个时候就需要同时用到绝对定位和相对定位以及 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 ( 
) } 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、本站所发布的文章以及附件仅限用于学习和研究目的;不得将用于商业或者非法用途;否则由此产生的法律后果,本站概不负责!

-六神源码网