前言
鼠标跟随框的作用如下图所示 ,可以在前端页面上 ,为我们后续的鼠标操作进行提示说明,提升用户的体验 。本文将通过多种方式去实现 ,从而满足不同场景下的需求 。
实现原理
实现鼠标跟随框的原理很简单 ,就是监听鼠标在页面上的坐标 ,然后利用相对定位(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>
{/* 鼠标跟随框 */}
<MousePositionModal
visible={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 (
<div
id="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 (
<div
id="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;
}
}
绝对定位和相对定位(相对于鼠标跟随框的父元素)
有时候我们可能并不需要在整个页面进行鼠标跟随框的提示 ,在某些情况下只需要鼠标在进入页面的部分区域才进行提示。
如下图所示:
这个时候就需要同时用到绝对定位和相对定位以及 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 (
<div id="mouse-position-demo" className="mouse-position-demo">
<MousePositionModal2
visible={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 (
<div
id="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实现多个场景下鼠标跟随提示框详解的详细内容 ,更多关于React鼠标跟随提示框的资料请关注本站其它相关文章!
声明:本站所有文章 ,如无特殊说明或标注,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时 ,禁止复制 、盗用、采集 、发布本站内容到任何网站 、书籍等各类媒体平台 。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 。