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

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前缀名]

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值