当前位置 : 主页 > 网络编程 > JavaScript >

React实现多个场景下鼠标跟随提示框详解

来源:互联网 收集:自由互联 发布时间:2023-02-08
目录 前言 实现原理 固定定位实现 MousePositionDemo MousePositionModal 绝对定位(相对于整个浏览器窗口) MousePositionDemo MousePositionModal 绝对定位和相对定位(相对于鼠标跟随框的父元素) M
目录
  • 前言
  • 实现原理
  • 固定定位实现
    • MousePositionDemo
    • MousePositionModal
  • 绝对定位(相对于整个浏览器窗口)
    • MousePositionDemo
    • MousePositionModal
  • 绝对定位和相对定位(相对于鼠标跟随框的父元素)
    • MousePositionDemo
    • MousePositionModal2
  • 最后

    前言

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

    实现原理

    实现鼠标跟随框的原理很简单,就是监听鼠标在页面上的坐标,然后利用相对定位(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;
      }
    }
    

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

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

    如下图所示:

    这个时候就需要同时用到绝对定位和相对定位以及 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">
                <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鼠标跟随提示框的资料请关注易盾网络其它相关文章!

    上一篇:React&nbsp;HOC高阶组件深入讲解
    下一篇:没有了
    网友评论