JS脚本 - 批量给所有指定标签追加Class属性

news2024/11/24 19:47:57

JS脚本 - 批量给所有指定标签追加Class属性

  • 前言
  • 一. 脚本
  • 二. 测试运行

前言

公司里我们有个应用引入了UBT埋点,记录了页面上所有的点击操作以及对应的点击按钮。但是我们看下来发现,我们需要给每个按钮加一个唯一标识做区分,并且这个ID是给UBT埋点专用的。那怎么办呢?

  • Id: 不合理,因为如果某个标签已经自带Id了,我们不太可能去覆盖它。
  • Class:合理,class属性可以加多个,也可以过滤。

一. 脚本

const fs = require('fs');
const path = require('path');
// 读取文件内容
const stack = [];
const classRegExp = /class="([^"]*)"/;
const idRegExp = /id="([^"]*)"/;
const args = process.argv.slice(2)
if (!args || args.length < 4) {
    console.log('参数不合法')
}

const TagMapping = [{
    Tag: 'a',
    ATagPre: '<a',
    ATagSuffix: '</a>'
}, {
    Tag: 'el-button',
    ATagPre: '<el-button',
    ATagSuffix: '</el-button>'
}, {
    Tag: 'el-dialog',
    ATagPre: '<el-dialog',
    ATagSuffix: '</el-dialog>'
}, {
    Tag: 'button',
    ATagPre: '<button',
    ATagSuffix: '</button>'
}]
const currentTagRegExp = new RegExp(`(<${'a'}\\s)([^>]*)(>)`, 'i');

function contentAddUbtClass(filePath, tag, classPre) {
    const tagInfo = TagMapping.filter(item => item.Tag === tag)[0];
    if (!tagInfo) {
        return;
    }
    const content = fs.readFileSync(filePath, 'utf8');
    let resultContent = ''
    const preLen = tagInfo.ATagPre.length;
    const stuffixLen = tagInfo.ATagSuffix.length;
    for (let i = 0; i < content.length; i++) {
        // a标签开始
        if (i + preLen < content.length && content.substring(i, i + preLen) === tagInfo.ATagPre) {
            stack.push(i);
        } else if (i + stuffixLen < content.length && content.substring(i, i + stuffixLen) === tagInfo.ATagSuffix) {
            if (stack.length > 0) {
                // 出栈,找到起始索引位置
                const start = stack.pop();
                // 栈为空的时候,才开始截取并替换,这决定了代码取的标签内容都是最外层的结构
                if (stack.length === 0) {
                    // a 标签
                    const aTagHtml = content.substring(start, i + stuffixLen);
                    const newHtml = addClass(aTagHtml, i, tag, classPre);
                    resultContent += newHtml;
                    i = i + stuffixLen - 1;
                }
            }
        } else {
            // 栈为空的时候,说明这个时候还没有识别到对应标签,可以添加其他内容。若识别到了对应标签,那么对应标签包裹的内容在这里不会添加
            if (stack.length === 0) {
                resultContent += content.charAt(i);
            }
        }
    }
    fs.writeFileSync(filePath, resultContent, 'utf8');
}

function addClass(content, index, tag, classPre) {
    // 匹配结果
    const classMatch = content.match(classRegExp);
    const idMatch = content.match(idRegExp);
    // class属性值
    let className;
    if (content.includes(classPre)) {
        return content;
    }
    if (idMatch) {
        // 如果匹配到了id属性,则在原有的class属性值上添加新的样式名称
        className = `${classPre}${tag}_` + idMatch[1];
        // 如果没有匹配到class属性,则在原有的文本中添加新的class属性
        if (classMatch) {
            // 追加class
            className = classMatch[1] + ` ${className}`;
        }
    } else if (classMatch) {
        // 如果没有匹配到id属性,但匹配到了class属性,则在原有的class属性值上添加新的样式名称
        className = classMatch[1] + ` ${classPre}${tag}_${index}`;
    } else {
        // 如果没有匹配到id属性和class属性,则生成一个新的class属性值
        className = `${classPre}${tag}_${index}`;
        // 在原有的文本中添加新的class属性
        // content = content.replace(currentClassRegExp, `<$1 class="${className}"`);
    }
    // 替换原有的class属性值
    return content.replace(currentTagRegExp, (match, p1, p2, p3) => {
    	// 判断标签原本是否包含了class属性
        if (p2.includes('class=')) {
            return `${p1}${p2.replace(classRegExp, `class="${className}"`)}${p3}`;
        } else {
            return `${p1}${p2} class="${className}"${p3}`;
        }
    });
}

// 遍历指定目录下的所有文件
function traverseDirectory(dirPath, extension, tag, classPre) {
    // 读取目录下的所有文件和子目录
    const files = fs.readdirSync(dirPath);
    // 遍历每个文件和子目录
    files.forEach((file) => {
        // 获取文件的完整路径
        const filePath = path.join(dirPath, file);
        // 判断文件是否是目录
        if (fs.statSync(filePath).isDirectory()) {
            // 如果是目录,则递归
            traverseDirectory(filePath, extension, tag, classPre);
        } else {
            // 如果是文件,则判断文件后缀名是否匹配指定的后缀名
            if (extension.includes(path.extname(filePath))) {
                // 如果匹配,则输出文件路径
                contentAddUbtClass(filePath, tag, classPre)
            }
        }
    });
}
traverseDirectory(args[0], args[1], args[2], args[3])

二. 测试运行

假设,我要给页面所有的a标签,添加一个class属性,固定的前缀是UBT_,准备一个html文件:
在这里插入图片描述
执行脚本:

node .\test.js './' '.html' 'a' 'UBT_' 
  1. node 脚本名称 [路径] [匹配的文件后缀(支持多个)] [匹配的标签名称] [增加的class前缀名]

结果如下:
在这里插入图片描述

大家也可以在这个脚本的基础上自行二创。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/752377.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

选读SQL经典实例笔记07_日期处理(下)

1. 一个季度的开始日期和结束日期 1.1. 以yyyyq格式&#xff08;前面4位是年份&#xff0c;最后1位是季度序号&#xff09;给出了年份和季度序号 1.2. DB2 1.2.1. sql select (q_end-2 month) q_start,(q_end1 month)-1 day q_endfrom (select date(substr(cast(yrq as c…

Linux系统编程(信号处理 sigacation函数和sigqueue函数 )

文章目录 前言一、sigaction二、sigqueue函数三、代码示例总结 前言 本篇文章我们来介绍一下sigacation函数和sigqueue函数。 一、sigaction sigaction 是一个用于设置和检查信号处理程序的函数。它允许我们指定信号的处理方式&#xff0c;包括指定一个函数作为信号处理程序…

AsyncImage, BackgroundMaterials, TextSelection, ButtonStyles 的使用

1. AsyncImage 异步加载图片 1.1 实现 /*case empty -> No image is loaded.case success(Image) -> An image succesfully loaded.case failure(Error) -> An image failed to load with an error.*/ /// iOS 15 开始的 API 新特性示例 /// 异步加载图片 struct As…

Ae 效果:CC Plastic

风格化/CC Plastic Stylize/CC Plastic CC Plastic&#xff08;CC 塑料&#xff09;效果用于创建具有塑料质感的图像或视频效果&#xff0c;它模拟了塑料材质的外观特性&#xff0c;包括光照反射、表面凹凸以及光泽效果等。 ◆ ◆ ◆ 效果属性说明 Surface Bump 表面凹凸 通过…

IoT 场景下 TDengine 与老牌时序数据库怎么选?看看这份TSBS报告

上周一&#xff0c;TDengine 正式发布了 IoT 场景下基于 TSBS 的时序数据库&#xff08;Time Series Database&#xff0c;TSDB&#xff09;性能基准测试报告。该报告模拟虚拟货运公司车队中一组卡车的时序数据&#xff0c;预设了五种卡车规模场景&#xff0c;在相同的 AWS 云环…

[Lesson 01] TiDB数据库架构概述

目录 一 章节目标 二 TiDB 体系结构 1 TiDB Server 2.1 TiKV 2.2 TiFlash 3 PD 参考 一 章节目标 理解TiDB数据库整体架构了解TiDB Server TiKV tiFlash 和 PD的主要功能 二 TiDB 体系结构 了解这些体系结构是如何实现TiDB的核心功能的 1 TiDB Server TiDB Serve…

记录--你知道Vue中的Scoped css原理么?

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 追忆Scoped 偶然想起了一次面试&#xff0c;二面整体都聊完了&#xff0c;该做的算法题都做出来了&#xff0c;该背的八股文也背的差不多了&#xff0c;面试官频频点头&#xff0c;似乎对我的基础和项…

云计算的学习(四)

四、云计算中的存储基础知识 1.云计算虚拟化中的存储架构 ①虚拟化存储 在虚拟化存储架构中&#xff0c;最底层为物理磁盘。 底层的硬件组成存储池&#xff0c;存储池分为NAS存储和SAN存储&#xff1b;NAS存储需要文件系统&#xff1b;SAN存储需要对存储池进行逻辑划分产生逻…

【VSCode | 使用技巧集锦】中文插件突然失效、配置单个工程(工作区)编码

目录 ✨技巧一&#xff1a;中文插件失效的解决办法✨技巧二&#xff1a;配置单个工程(工作区)编码 ✨技巧一&#xff1a;中文插件失效的解决办法 问题描述&#xff1a;VSCode之前安装了中文插件&#xff0c;可以正常汉化&#xff0c;用了一段时间都没问题&#xff0c;今天打开v…

springboot+webscoket通信功能

1. 背景 项目上需要对某个页面的设计功能&#xff08;低代码&#xff09;进行最简单的多人协同&#xff0c;有以下需求点&#xff1a; &#xff08;1&#xff09;第一个进入该设计页面的人给编辑权限&#xff0c;后进入的所有人给在线&#xff08;可申请编辑&#xff09;权限 …

使用MQTTX和前端vue进行通讯

需求&#xff1a;根据后端给的接口&#xff0c;前端实现消息订阅和消息加密连接操作&#xff0c;不走后端直接和硬件设备进行操作 1.下载mqttx 官网链接&#xff1a;MQTTX: Your All-in-one MQTT Client Toolbox 根据自己电脑选择不同的操作系统&#xff0c;默认下载后是英文…

金鸣表格识别中何时应勾选“手写”选项?

在金鸣表格文字识别系统的表格识别模块中&#xff0c;有个“手写”的复选框可供用户选择性使用。这里的“手写”是手写识别的简称&#xff0c;设置此项的目的是为了让用户更准确地识别手写的表格图片中的文字。为何要单独设置这个选项而不是由程序全自动地进行处理呢&#xff1…

【GitOps系列】K8s极简实战

文章目录 示例应用介绍部署应用到k8s 如何使用命名空间隔离团队及应用环境&#xff1f;如何为业务选择最适合的工作负载类型&#xff1f;如何解决服务发现问题&#xff1f;如何迁移应用配置&#xff1f;如何将集群的业务服务暴露外网访问&#xff1f;如何保障业务资源需求和自动…

JavaWeb(3)——HTML、CSS、JS 快速入门

一、JavaScript 运算符 • 赋值运算符&#xff08; &#xff09; 赋值运算符执行过程&#xff1f; 将等号右边的值赋予给左边, 要求左边必须是一个容器 出现是为了简化代码, 比如让 let age 18 &#xff0c;age 加 2 怎么写呢 let age 18age 2console.log(age)age * 2con…

html+JavaScript实现一个好看的颜色码查询器,支持查询、转换、颜色选择器和颜色码对照表

前言 相信大家平时工作的时候应该会经常用到颜色码吧&#xff0c;比如说想找个好看的颜色&#xff0c;或者有个颜色码但是不知道这个码是什么颜色的&#xff0c;这个时候我们就可以用颜色码对照表或者颜色码查询来查看了。 当然也可以用截图软件或者取色器或者PS来查看&#…

如何有效检测、识别和管理 Terraform 配置漂移?

作者&#xff5c;Krishnadutt Panchagnula 翻译&#xff5c;Seal软件 链接&#xff5c;https://betterprogramming.pub/detecting-identifying-and-managing-terraform-state-drift-997366a74537 在理想的 IaC 世界中&#xff0c;我们所有的基础设施实现和更新都是通过将更新的…

【高并发】高并发架构实战:从需求分析到系统设计

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 很多软件工程师的职业规划是成为架构师&#xff0c;但是要成为架构师很多时候要求先有架构设计经验&#xff0c;而不做架构师又怎么会有架构设计经验呢&#xff1f;那么要如何获得架构设…

Cesium 测距、测面功能实现

参考博主 功能代码参考 新需求&#xff1a;点击测距&#xff0c;此时画线逻辑已生成到运行缓存中&#xff0c;如果 用户误触测距&#xff0c;想撤销&#xff0c;如何操作&#xff1f; 代码&#xff1a; // 重置画图resetDraw(){// 清除可能会用到的监听事件if (this.handle…

操作系统17:外存组织方式和文件存储管理

目录 1、外存的组织方式 &#xff08;1&#xff09;连续组织方式 &#xff08;2&#xff09;链接组织方式 2.1 - 隐式链接 2.2 - 显式链接 &#xff08;3&#xff09;索引组织方式 3.1 - 单级索引组织方式 3.2 - 多级索引组织方式 3.3 - 增量式索引组织方式 2、文件存…

【操作系统】几种基本页面置换算法的基本思想和流程图

目录 一、概述二、最佳置换算法&#xff08;OPT&#xff09;三、先进先出置换算法&#xff08;FIFO&#xff09;四、最近最久未使用置换算法&#xff08;LRU&#xff09;五、三种页面置换算法优缺点对比六、运行结果七、总结 一、概述 在地址映射过程中&#xff0c;若在页面中发…