首页 前端知识 VUE3 Vite ts实现浏览器点击元素打开对应的vue文件并定位到对应内容区域

VUE3 Vite ts实现浏览器点击元素打开对应的vue文件并定位到对应内容区域

2024-09-09 00:09:18 前端知识 前端哥 943 906 我要收藏

1.背景

目前的许多项目都是使用vue进行开发的,当一个vue项目做大时维护起来非常麻烦,当我们需要找到某个文件的时候非常麻烦,传统快速定位到某个文件可以使用类名、或者路由路径等方式找到对应的文件。

c1de1006c3fa4241a23a51b5e2ba3514.gif

2、vue devTools介绍

vue devTools是vue开发的一个插件,它同时也具备着能够快速定位到某个文件的功能:

648a6be7a2da43d3adbc6344bf9b39ba.png

点击这个图标然后点击某个元素即可打开某个vue文件的详情

617788489b7441b0a81548aa0ae819e7.png

点击右上角的图标即可在编辑器中打开该文件

3、自定义快速打开元素插件

虽然vue提供的插件已经足够满足我们日常开发需求了,但是我觉得速度依然不够快于是决定采用自定义插件的方式实现按住shift+鼠标左键的方式快速打开某个元素对应的vue文件。

3.1 以VUE3+Vite为例子

创建openCodeClient.ts文件,用于向当前server端发起网络请求

import axios from 'axios'

function openEditor(filePath: string): void {
    console.log(filePath);
  axios
    .get('/code', {
      params: { filePath }
    })
    .catch(error => {
      console.error(error)
    })
}

function getFilePath(element: HTMLElement | null): string | null {
  if (!element || !element.getAttribute) return null
  const codeLocation = element.getAttribute('code-location')
  if (codeLocation) {
    return codeLocation
  }
  return getFilePath(element.parentElement)
}

function openCode(e: MouseEvent): void {
  const isShiftKey = e.shiftKey
  const isMetaKey = e.metaKey
  if (isShiftKey || isMetaKey) {
    e.preventDefault()
    const target = e.target as HTMLElement
    const filePath = getFilePath(target)
    if (filePath) {
      openEditor(filePath)
    }
  }
}

function init(): void {
  document.addEventListener('click', openCode, true)
}

export default { init }

3.2 创建server.ts文件

用于接收client端发起的网络请求并打开vscode对应的vue文件

import { exec } from 'child_process'
import type { Plugin } from 'vite';
import { IncomingMessage, ServerResponse } from 'http'

function openCodeFile(path: string): void {
  exec(`code -r -g ${path}`, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error.message}`)
      return
    }
    if (stderr) {
      console.error(`Error output: ${stderr}`)
      return
    }
    console.log(`Command output: ${stdout}`)
  })
}

const codeServer = (): Plugin => ({
  name: 'open-code-vite-server',
  configureServer(server) {
    server.middlewares.use((req: IncomingMessage, res: ServerResponse, next: () => void) => {
      const url = new URL(req.url || '', `http://${req.headers.host}`)
      const filePath = url.searchParams.get('filePath')
      if (url.pathname === '/code' && filePath) {
        openCodeFile(filePath)
        res.statusCode = 200
        res.end()
      } else {
        next()
      }
    })
  }
})

export default codeServer

3.3 创建vite-plugin-add-code-location.ts文件

用来给当前页面每一个元素添加一个自定义属性,属性名叫add-code-location,值是对应的文件路径+代码行

import type { Plugin } from 'vite';

export default function addCodeLocationPlugin(): Plugin {
  return {
    name: 'add-code-location',
    transform(code: string, id: string) {
      return sourceCodeChange(code, id);
    },
  };
}

function sourceCodeChange(source: string, resourcePath: string): string {
  // 只对 .vue 文件进行处理
  if (resourcePath.endsWith('.vue')) {
    const templateMatch = source.match(/<template>([\s\S]*?)<\/template>/);
    if (templateMatch) {
      const templateContent = templateMatch[1];
      const modifiedTemplate = codeLineTrack(templateContent, resourcePath);

      // 替换原有的 template 内容
      source = source.replace(templateContent, modifiedTemplate);
    }
  }
  return source;
}

function codeLineTrack(str: string, resourcePath: string): string {
  const lineList = str.split('\n');
  const newList = lineList.map((item, index) => addLineAttr(item, index + 1, resourcePath));
  return newList.join('\n');
}

function addLineAttr(lineStr: string, line: number, resourcePath: string): string {
  const reg = /<[\w-]+/g;
  let leftTagList = lineStr.match(reg);
  if (leftTagList) {
    leftTagList = Array.from(new Set(leftTagList));
    leftTagList.forEach(item => {
      if (item && item.indexOf('template') === -1) {
        const regx = new RegExp(`${item}`, 'g');
        const location = `${item} code-location="${resourcePath}:${line}"`;
        lineStr = lineStr.replace(regx, location);
      }
    });
  }
  return lineStr;
}

4、配置vite.config.ts

在vite.config.ts中引入我们写好的自定义插件,我把两个函数都放在最前面了因为放后面可能会被其它插件干扰到

3186c5714e03474692d492b592dbe202.png

5、配置tsconfig.node.json

这里的主要目的是让vite能识别根目录下的文件不然在vite.config.ts中引入插件路径会报错,或者不生效的情况

98ebbb0502bb4d3f883d6f4d093a91fc.png

识别src下的所有文件,让它能够识别出我们自定义的插件

6、在main.ts中加载全局监听事件监听内容

判断当前是否属于开发环境,如果是则可以触发监听,比较生产根本不需要,监听用户如果按住shift+左键点击某个元素则会获取到该元素上的code-location属性拿到文件路径包括行号

import openCodeClient from '@/utils/openCodeClient';
if (import.meta.env.MODE === 'development') {
  openCodeClient.init();
  // 添加全局点击事件监听
  // 添加全局点击事件监听
  document.addEventListener('click', (event) => {
    const target = event.target as HTMLElement;
    const codeLocation = target.getAttribute('code-location');
    // 检查是否按住了 Shift 键并且点击了左键
    if (event.shiftKey && event.button === 0 && codeLocation) {
      fetch(`/code?filePath=${encodeURIComponent(codeLocation)}`)
        .then((response) => {
          if (response.ok) {
            console.log('Code opened successfully');
          } else {
            console.error('Failed to open code');
          }
        })
        .catch((error) => {
          console.error('Error fetching code location:', error);
        });
    }
  });
}

7、测试结果

如果插件正常加载成功,按f12打开元素审查会看到每个元素都有一个自定义属性,如果不成功则再检查看看是哪里有问题了

7c8788ceeb2643eaab23e2a1fb50fa80.png

该项目借鉴了一位前端大佬的文章,文章链接。文章里有详细的设计思路和代码片段。 本来打算直接用大佬的项目,但是对方说暂时只在他们公司内部使用,故本人自己写了一个简单版的。

 

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17992.html
标签
评论
发布的文章

安装Nodejs后,npm无法使用

2024-11-30 11:11:38

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!