前端细碎知识点
约 1091 字大约 4 分钟
2026-03-14
日常前端开发里,总会碰到不少这类内容:或是一知半解、无需深入钻研却偶尔会用到的知识点,或是更简洁优雅的代码写法,也有那些不想一遇到就去查 AI、希望自己能记牢的小细节。
这些内容并不会影响基础功能的正常开发,却能让代码更精致、开发更省心。特此记录下来,方便随时回顾查阅,沉淀属于自己的前端小知识库。
XLSX 导出时,百分比数据如何设置为数值格式?
核心逻辑,XLSX 不能识别 '50%',会识别为字符串,所以,我们要先转成 0.5 这样的数值,然后将单元格格式设置为 '0.00%'。
XLSX 里面单元格 v 表示数值,t表示类型(n即 number),z 表示格式(0.00%表示格式保留 2 位小数)
import * as XLSX from 'xlsx';
function exportPercent() {
// 数据是字符串 '50%'
const data = [
['姓名', '进度'],
['张三', '50%'],
['李四', '75%'],
];
const worksheet = XLSX.utils.aoa_to_sheet(data);
const range = XLSX.utils.decode_range(worksheet['!ref']);
// 遍历数据单元格(跳过表头 R=0)
for (let C = range.s.c; C <= range.e.c; C++) {
for (let R = 1; R <= range.e.r; R++) {
const cellAddr = XLSX.utils.encode_cell({ r: R, c: C });
const cell = worksheet[cellAddr];
if (cell && typeof cell.v === 'string' && cell.v.endsWith('%')) {
cell.t = 's'; // 字符串类型保留
// 但 Excel 不会识别字符串为百分比,需要转成数值
const num = parseFloat(cell.v) / 100;
cell.v = num;
cell.t = 'n';
cell.z = '0%';
}
}
}
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, '导出');
XLSX.writeFile(workbook, 'test.xlsx');
}现在有一个 display:flex的盒子。现在里面有 4 个元素。如何让最后一个元素在这个盒子的末尾。
场景类似于,最后一个元素是一个叉号按钮。
给最后一个元素设置 margin-left: auto即可
但若是只有 2 个元素的时候,不给margin-auto怎么做?
用 CSS 选择器监测元素数量
.container > :last-child:not(:nth-child(2)) {
margin-left: auto;
}3 个以上才生效可以这样写
.container > :first-child:nth-last-child(n+3) ~ :last-child {
margin-left: auto;
}"第一个元素同时是倒数第3个或更后",即总共至少 3 个元素时才匹配。
package.json 里的 script 命令传参数
"ai:popup": "node processByaI/ai_popup.js $npm_config_file $npm_config_type",当你运行 npm 脚本时,可以通过 --参数名=值 的方式传递参数:
npm run ai:popup --file=xxx --type=xxxJS 脚本里如何动态 import
// 方式1:静态 import 无法使用变量
// ❌ 错误
const moduleName = 'handlebars';
import moduleName from moduleName; // 报错
// ✅ 方式2:使用 dynamic import
const moduleName = 'handlebars';
const Handlebars = await import(moduleName);
// ✅ 方式3:本地文件动态导入
import { fileURLToPath } from 'url';
import * as path from 'path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// 动态导入同目录下的模块
const moduleName = 'utils';
const utils = await import(`./${moduleName}.js`);
utils.default.someFunction(); // 如果是 default 导出
// 或者
import(`./${moduleName}.js`).then(module => {
module.someFunction();
});
// 动态导入处理函数
async function loadProcessor(name) {
const module = await import(`./processors/${name}.js`);
return module.default || module;
}
// 使用
const processor = await loadProcessor('user');name里面可能会有上面数组里 5 个数据的值,要求写一个函数判断
function getMatchedKeyword(name, keywords = ['city', 'sp', 'cp', 'fleet', 'agent']) {
if (!name) return null;
return keywords.find(keyword => name.includes(keyword)) || null;
}
// 使用
getMatchedKeyword('open_city'); // 'city'
getMatchedKeyword('sp_id'); // 'sp'
getMatchedKeyword('status'); // null写一个函数,一个字符串转成这样 bannerTypeOption。
function toCamelCaseOption(str) {
if (!str) return str;
// 如果包含下划线,转换为驼峰
if (str.includes('_')) {
// 将字符串中 下划线 + 任意字符 的组合,替换为 大写的该字符,从而去掉下划线、实现小驼峰格式。
// \w 匹配字母 / 数字 / 下划线
return str
.replace(/_(\w)/g, (_, letter) => letter.toUpperCase()) + 'Option';
}
// 没有下划线,直接加 Option
return str + 'Option';
}
// 测试
toCamelCaseOption('banner_type'); // bannerTypeOption
toCamelCaseOption('city_id'); // cityIdOption
toCamelCaseOption('sp_cp'); // spCpOption
toCamelCaseOption('cityId'); // cityIdOption
toCamelCaseOption('status'); // statusOption写一个JS 函数,/manage/agent/info。要求取这种格式的字符串,最后两个 agent,info。组成 agentInfo 的形式
function formatApiName(url) {
// 去掉 query 参数
const path = url.split('?')[0];
// 分割并过滤空字符串
const parts = path.split('/').filter(Boolean);
if (parts.length < 2) {
return parts[0] || 'request';
}
const lastTwo = parts.slice(-2); // 取最后两个,可以直接用 slice(-2),从倒数第二个开始截取
// 第二个参数首字母大写
return lastTwo[0] + lastTwo[1].charAt(0).toUpperCase() + lastTwo[1].slice(1);
}
// 测试
formatApiName('/manage/agent/info?action=1'); // agentInfo
formatApiName('/user/list'); // userList
formatApiName('/api'); // api
formatApiName(''); // request