一个 页面元素选中高亮 Hook

# 图例

An image

# 使用

  • 在开发环境下,按住 command 后,鼠标移入到页面上的 dom 元素,可以被点击的 dom 元素会出现蓝色边框

  • 点击 dom 元素之后触发 click 事件,将 dom 上的属性data-sf``data-sl加入到参数中,然后去请求接口vscode/openfile

  • 后续操作由接口vscode/openfile执行

    • 接口vscode/openfile会根据传入的data-sf``data-sl,精准打开 vscode,并跳转到与之对应的源码位置

    • 很大程度上方便了开发者在开发环境下的调试;提供了再多人协作的项目中,改 bug 时、改其他人代码时候,快速定位代码的功能

# 实现代码

点击 展开/收起 jsx 代码
/**
 * @des 结合插件跳转到 vscode,在页面上元素高亮
 */

import { useState, useEffect } from 'react';

export const useHighlightOnCommand = () => {
  const [isCommandPressed, setIsCommandPressed] = useState(false);
  const [highlightedElement, setHighlightedElement] = useState(null);

  useEffect(() => {
    const handleClick = (event) => {
      if (event.metaKey) {
        event.preventDefault();
        event.stopPropagation();

        const { target } = event;

        const filePath = target.getAttribute('data-sf');
        const lineNumber = target.getAttribute('data-sl');
        const columnNumber = 0;

        const url = new URL('/vscode/openfile', window.location.origin);
        url.searchParams.append('filePath', filePath);
        url.searchParams.append('lineNumber', lineNumber);
        url.searchParams.append('columnNumber', columnNumber);

        console.log('filePath', filePath, lineNumber);

        if (filePath && lineNumber) {
          fetch(url.href, {
            method: 'GET',
          }).catch((err) => console.error('跳转vscode:', err));
        } else {
          console.error('dom的babel信息错误');
        }
      }
    };

    const handleKeyDown = (event) => {
      if (event.metaKey) {
        setIsCommandPressed(true);
      }
    };

    const handleKeyUp = (event) => {
      if (!event.metaKey) {
        setIsCommandPressed(false);
        if (highlightedElement) {
          highlightedElement.classList.remove('can-open-vscode');
          setHighlightedElement(null);
        }
      }
    };

    const handleMouseMove = (event) => {
      if (isCommandPressed) {
        let targetElement = event.target;

        // 向上查找,直到找到具有 data-sf 属性的元素或到达根元素
        while (targetElement && !targetElement.getAttribute('data-sf')) {
          targetElement = targetElement.parentElement;
        }

        if (targetElement) {
          if (highlightedElement && highlightedElement !== targetElement) {
            highlightedElement.classList.remove('can-open-vscode');
          }

          if (!highlightedElement || highlightedElement !== targetElement) {
            targetElement.classList.add('can-open-vscode');
            setHighlightedElement(targetElement);
          }
        } else {
          if (highlightedElement) {
            highlightedElement.classList.remove('can-open-vscode');
            setHighlightedElement(null);
          }
        }
      }
    };

    if (process.env.NODE_ENV === 'development') {
      window.addEventListener('click', handleClick, true);
      document.addEventListener('keydown', handleKeyDown);
      document.addEventListener('keyup', handleKeyUp);
      document.addEventListener('mousemove', handleMouseMove);
    }

    return () => {
      window.removeEventListener('click', handleClick, true);
      document.removeEventListener('keydown', handleKeyDown);
      document.removeEventListener('keyup', handleKeyUp);
      document.removeEventListener('mousemove', handleMouseMove);
    };
  }, [isCommandPressed, highlightedElement]);

  return null; // 这个 Hook 不需要返回任何内容
};