- 作者:老汪软件技巧
- 发表时间:2024-09-30 04:00
- 浏览量:
手把手带你自己实现一个HTML 结构跳转对应代码器
大家在写前端代码的时候,可能经常遇到这种情况:想要知道页面中的某个元素是在哪段 JSX 代码里定义的,然后翻源码找对应的地方。今天我们来实现一个非常简单的功能——当你在网页上 hover 或点击某个元素时,它会自动打开 VSCode,跳转到对应的源码文件并定位到 JSX 定义的具体行数。
思路也非常简单,主要分为三步:
1. 配合编译器获取每个 JSX 元素的源文件路径和起始位置(行数)。
2. 在入口函数中为所有 JSX 元素添加监听事件,动态检测 DOM 变化,并根据用户操作预装点击事件。
3. 用获取到的路径和行数信息打开 VSCode。
第一步:编译器获取 JSX 源文件路径和起始行数
我们要在打包时,利用 Babel 插件给每个 JSX 元素添加一个 data-src 属性,这个属性会记录 JSX 元素所在的源文件路径和它的起始行数。这样,我们就能把每个 HTML 元素和它的 JSX 代码一一对应起来。
具体代码实现如下:
// babel-plugin-add-data-src.js
export default function ({ types: t }) {
return {
visitor: {
JSXOpeningElement(path) {
const { node } = path;
// 检查是否已经有 data-src 属性,避免重复添加
const hasDataSrc = node.attributes.some(attr =>
t.isJSXAttribute(attr) && attr.name.name === "data-src"
);
if (!hasDataSrc) {
// 获取当前文件的路径
const filePath = path.hub.file.opts.filename;
// 获取 JSX 元素的起始行数
const lineNumber = node.loc.start.line;
// 把路径和行号作为 data-src 的值
const dataSrcValue = `${filePath}:${lineNumber}`;
// 创建 data-src 属性并加到 JSX 元素上
const dataSrcAttr = t.jsxAttribute(
t.jsxIdentifier("data-src"),
t.stringLiteral(dataSrcValue)
);
node.attributes.push(dataSrcAttr);
}
}
}
};
}
把这段 plugin 添加到你的 Babel 编译里, 这里演示下 vite 的用法
注意一定要禁用原有 Babel 处理 jsx
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path';
// https://vitejs.dev/config/
// 自定义的 Babel 插件路径
// @ts-ignore
const addDataSrcPlugin = path.resolve(__dirname, './babel-plugin-add-data-src.cjs');
export default defineConfig({
plugins: [
react({
// 禁用 esbuild 处理 JSX
jsxRuntime: 'automatic',
babel: {
plugins: [addDataSrcPlugin], // 添加自定义的 Babel 插件
},
}),
],
});
第二步:监听 DOM 变化并添加事件
下一步就是为页面中所有带有 data-src 属性的元素添加事件监听。我们要监听键盘(Alt/Option 键)和鼠标的事件,当鼠标 hover 到某个带 data-src 的元素时,会给这个元素加个边框;当同时按下 Alt/Option 键并点击元素时,会获取它的 data-src 信息,打开对应的文件。
代码如下:
// 主入口函数
export default function setupSrcHighlighter() {
// 监听 DOM 变化
const observer = new MutationObserver(handleDomChange);
observer.observe(document.body, { childList: true, subtree: true });
// 初始处理现有的元素
handleDomChange();
// 添加键盘和鼠标事件监听
let altKeyPressed = false;
document.addEventListener('keydown', (e) => {
if (e.key === 'Alt' || e.key === 'Option') {
altKeyPressed = true;
}
});
document.addEventListener('keyup', (e) => {
if (e.key === 'Alt' || e.key === 'Option') {
altKeyPressed = false;
}
});
// 鼠标移动时处理 hover 效果
document.addEventListener('mousemove', (e) => {
if (altKeyPressed) {
const element = getHoveredElementWithDataSrc(e.target);
if (element) {
removeBordersFromAll();
addBorderToElement(element);
}
} else {
removeBordersFromAll();
}
});
// 当 Alt + 左键同时按下时,打开 VSCode
document.addEventListener('click', (e) => {
if (altKeyPressed && e.button === 0) {
const element = getHoveredElementWithDataSrc(e.target);
if (element) {
const dataSrc = element.getAttribute('data-src');
if (dataSrc) {
openFileInVSCode(dataSrc);
}
}
}
});
}
// 处理 DOM 变化时查找所有带 data-src 的元素
function handleDomChange() {
const elements = document.querySelectorAll('[data-src]');
elements.forEach(element => {
element.style.cursor = 'pointer'; // 提供用户交互反馈
});
}
// 查找当前 hover 的带 data-src 的元素
function getHoveredElementWithDataSrc(target) {
return target.closest('[data-src]');
}
// 添加等宽高边框
function addBorderToElement(element) {
element.style.outline = '2px solid blue';
}
// 移除所有元素的边框
function removeBordersFromAll() {
const elements = document.querySelectorAll('[data-src]');
elements.forEach(element => {
element.style.outline = 'none';
});
}
第三步:用获取的信息打开 VSCode
我们获取到 data-src 的值后,会利用 VSCode 提供的 vscode://file/ URI 方案来打开指定的文件和行号。下面是打开 VSCode 的代码:
// 打开 VSCode,假设 data-src 包含文件路径和行号
function openFileInVSCode(dataSrc) {
// 使用 `vscode://file` URI 打开文件,假设 dataSrc 是 'filePath:lineNumber'
const [filePath, lineNumber] = dataSrc.split(':');
const vscodeUri = `vscode://file/${filePath}:${lineNumber}`;
// 使用 window.open 或 location.href 打开 VSCode
window.location.href = vscodeUri;
}
在你的程序main 函数中运行这个setupSrcHighlighter函数即可
看看效果
PS:业务代码写太多了敲小工具还是很开心的,感谢老爷阅读,希望对你有所帮助