webpack源码分析——truncateArgs函数

一、truncateArgs 函数

函数功能

该函数可以用于用户界面中的文本截断,确保长文本在有限的显示空间内能够适当显示,并且用户可以了解到部分文本已被省略。

函数参数

  • args:参数数组。用于输出到界面上
  • maxLength:当前界面上可容纳最大可输出字符长度。根据当前参数对要输出的内容进行转换(具体转换如下)

假设args中只有一个参数

js 复制代码
let args = ['sksddsloxcc']
  • 当 0 < maxLength <=3时,输出args0中的字符(计算公式:args\[0.slice(-availableLength)])。比如:maxLength = 1,输出 c 。maxLength = 2 输出 cc
  • 当 3 < maxLength < arg0.length时, 输出args0中的字符(计算公式:"..." + args\[0.slice(-availableLength + 3)])。比如:maxLength = 4 时,输出...c。maxLength = 5时,输出...cc
  • 当 maxLength >= arg0.length 时,直接返回arg0完整字符

假设args中有多个参数

js 复制代码
let args = ['sksddsloxcc', 'dfdffrvxgsvchsgcvgcdcdsvcdbcuydcedvc', '2345vgsscgvschghgvghsgc', '35677vsgscysvcvgyvgv']

当多个参数时,truncateArgs 函数总是想着把多个参数内容,最大化输出到界面上,因此呈现如下规律。

  1. args中所有值的长度和6取最小值最后再相加的和(maxLength-参数间空格数)做比较

    js 复制代码
    maxLength - lengths.length + 1 < arraySum(lengths.map(i => Math.min(i, 6)))
  2. 如果界面的空间放不下,则从右向左去掉一个参数,递归(这里args中数量会有变化),再做比较,如果多个最大值6相加小于maxLength - lengths.length + 1,则进入第3步

  3. 获取当前args数组中参数字符串长度总和并和当前maxLength - lengths.length + 1比较。如果当前内容放的下就直接返回。放不下则进入第4步

    js 复制代码
    let currentLength = arraySum(args.map(a => `${a}`.length));
    // Check if all fits into maxLength
    if (currentLength <= maxLength - lengths.length + 1) return args;
  4. 因为当前界面放不下当前参数,于是就截断参数(args)中最长的一个。比如:'dfdffrvxgsvchsgcvgcdcdsvcdbcuydcedvc',截取一次做一下比较看当前参数的总长度是否小于或等于可用长度。如果时,就进行输出。不是的话就再次进行挑选参数(args)中最长的一个(注意:本次挑选最长的一个和第一次最长的一个不一定是同一个字符,因为第一次已经对它进行了截取),进行截取

最终效果如下

源码分析

  1. 对当前args数组计算每一项值的长度,存为lengths,同时获取当前界面可用长度availableLength

    js 复制代码
    const lengths = args.map(a => `${a}`.length);
    const availableLength = maxLength - lengths.length + 1;

    maxLength - lengths.length + 1的意思是 空格也占用空间

  2. 对args数组中只有一项并且availableLength大于0

    js 复制代码
    if (availableLength > 0 && args.length === 1) {
    	if (availableLength >= args[0].length) { // 当前界面可用长度完全够用
    		return args;
    	} else if (availableLength > 3) { // 当前界面可用长度大于3,则需要拦截并伴随'...'
    		return ["..." + args[0].slice(-availableLength + 3)];
    	} else { // 当前界面可用长度太短了,只能显示几个字符
    		return [args[0].slice(-availableLength)]; // 这里是负号,注意顺序
    	}
    }
  3. 多参数情况。 检查lengths中每一项之和是否超过界面可用长度,超过了进行递归

    js 复制代码
    if (availableLength < arraySum(lengths.map(i => Math.min(i, 6)))) {
    	// remove args
    	if (args.length > 1)
    		return truncateArgs(args.slice(0, args.length - 1), maxLength);
    	return [];
    }

    如果lengths中长度超过6时按照6算,是为了实现在不充裕的界面可用长度下该字符最多显示的数量。就是6个字符。即'...abc'

    当前界面可用长度为16,去掉空格剩余14。因为装不下所以输出内容,通过availableLength < arraySum(lengths.map(i => Math.min(i, 6))),判断发现可以装下args数组中前3项。所以就打印了前3项内容。至于为什么第1和3项内容有'...',下面会有说明

  4. 检查当前lengths中所有项之和是否超过界面可用长度,没有的话就全部返回。有就需要进行截断最长的项

js 复制代码
let currentLength = arraySum(lengths);

// Check if all fits into maxLength
if (currentLength <= availableLength) return args;
  1. 截断最长的项,直到总长度符合要求为止。否则进行循环♻️
js 复制代码
while (currentLength > availableLength) {
	const maxLength = Math.max(...lengths); // 获取当前最长项的长度
	const shorterItems = lengths.filter(l => l !== maxLength); // 过滤得到不长的项
	const nextToMaxLength =
		shorterItems.length > 0 ? Math.max(...shorterItems) : 0; // 在不长项中找到次长项(比着最长项短点)
	const maxReduce = maxLength - nextToMaxLength; // 获取最长项和次长项之间的差距
	let maxItems = lengths.length - shorterItems.length; // 获取最长项个数,因为有可能lengths有多个最长项
	let overrun = currentLength - availableLength; // 获取溢出的长度
	for (let i = 0; i < lengths.length; i++) {
		if (lengths[i] === maxLength) {
			// 这里需要比较overrun / maxItems和maxReduce的最小值,以免多减
			const reduce = Math.min(Math.floor(overrun / maxItems), maxReduce);
			lengths[i] -= reduce;
			currentLength -= reduce;
			overrun -= reduce;
			maxItems--;
		}
	}
}
  1. 对截取后的项进行输出
js 复制代码
return args.map((a, i) => {
	const str = `${a}`;
	const length = lengths[i];
	if (str.length === length) {
		return str;
	} else if (length > 5) {
		return "..." + str.slice(-length + 3);
	} else if (length > 0) {
		return str.slice(-length);
	} else {
		return "";
	}
});
相关推荐
Csvn5 小时前
OpenSpec 详细使用教程
前端
之歆6 小时前
Day19_LESS 完全指南——从入门到工程实践
前端·css·less
云水一下7 小时前
HTML5 从入门到精通:实战收官——从零搭建完整静态网站,综合运用所有知识
前端·html5
不总是7 小时前
Windows 系统 Node.js 免安装版(zip)安装与配置教程(2026 最新)
前端·windows·node.js
冬奇Lab7 小时前
每日一个开源项目(第105篇):Twenty - 跳出 Salesforce 的圈套,定义现代开源 CRM
前端·后端·开源
zhangyao9403308 小时前
开发pc端时,表格的高度怎么设置才能铺满页面
前端·javascript·elementui
kjs--9 小时前
浏览器书签执行脚本
前端
之歆9 小时前
Day16_JavaScript 轮播图与事件工程实战(下篇)
服务器·开发语言·前端·javascript·网络·性能优化
沄媪9 小时前
CSRF 跨站请求伪造
前端·ctf·csrf
kyriewen9 小时前
我关掉了Copilot:因为我写的代码出现在了别人的建议里
前端·javascript·ai编程