webpack源码分析——truncateArgs函数

一、truncateArgs 函数

函数功能

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

函数参数

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

假设args中只有一个参数

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

假设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 "";
	}
});
相关推荐
栈老师不回家10 分钟前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙15 分钟前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠20 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
小远yyds40 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
吕彬-前端2 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱2 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai2 小时前
uniapp
前端·javascript·vue.js·uni-app
bysking3 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓3 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4113 小时前
无网络安装ionic和运行
前端·npm