網站首頁 編程語言 正文
前言
鼠標跟隨框的作用如下圖所示,可以在前端頁面上,為我們后續的鼠標操作進行提示說明,提升用戶的體驗。本文將通過多種方式去實現,從而滿足不同場景下的需求。
實現原理
實現鼠標跟隨框的原理很簡單,就是監聽鼠標在頁面上的坐標,然后利用相對定位(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; } }
最后
本文結合實例,詳細的介紹了鼠標跟隨框在三種場景下的三種具體實現的方法
原文鏈接:https://juejin.cn/post/7148963526021906469
相關推薦
- 2022-07-24 基于python實現雙向鏈表_python
- 2022-04-10 Qt實現部件透明及陰影效果的示例代碼_C 語言
- 2022-12-29 python解決循環依賴的問題分析_python
- 2022-05-29 C#對XmlHelper幫助類操作Xml文檔的通用方法匯總_C#教程
- 2022-07-02 運行react項目時出現Uncaught ReferenceError: process is no
- 2022-06-01 Androidstudio調用攝像頭拍照并保存照片_Android
- 2022-11-10 golang?常用定時任務匯總_Golang
- 2022-10-29 umi pro-layout : 某個頁面 禁用/移除 pro-layout ( 比如: 登錄頁不需
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支