后续会持续记录。
1.获取指定cookie
/**
* @description 从cookie中获取指定值
* @param {string} name cookie名称
* @returns {string | null} cookie值,如果不存在则返回null
*/
export const getCookie = (name: string): string | null => {
if (typeof document === 'undefined') return null;
const cookies = document.cookie.split(';');
for (const cookie of cookies) {
const [cookieName, cookieValue] = cookie.trim().split('=');
if (cookieName === name) {
return decodeURIComponent(cookieValue || '');
}
}
return null;
};
2.存储cookie值
/**
* @description 设置cookie值
* @param {string} name cookie名称
* @param {string} value cookie值
* @param {object} options 可选配置项
* @param {Date | number} options.expires 过期时间
* @param {string} options.path 路径
* @param {string} options.domain 域名
* @param {boolean} options.secure 是否只在HTTPS下传输
* @param {string} options.sameSite 同站策略
*/
export const setCookie = (
name: string,
value: string,
options: {
/** 过期时间 */
expires?: Date | number;
/** 路径 */
path?: string;
/** 域名 */
domain?: string;
/** 是否只在HTTPS下传输 */
secure?: boolean;
/** 同站策略 */
sameSite?: 'strict' | 'lax' | 'none';
} = {},
): void => {
if (typeof document === 'undefined') return;
const { expires, path = '/', domain, secure = false, sameSite = 'lax' } = options || {};
let cookieString = `${name}=${encodeURIComponent(value)}`;
if (expires) {
if (typeof expires === 'number') {
const date = new Date();
const days = expires * 24 * 60 * 60 * 1000;
date.setTime(date.getTime() + days);
cookieString += `; expires=${date.toUTCString()}`;
} else {
cookieString += `; expires=${expires.toUTCString()}`;
}
}
cookieString += `; path=${path}`;
if (domain) {
cookieString += `; domain=${domain}`;
}
if (secure) {
cookieString += '; secure';
}
cookieString += `; sameSite=${sameSite}`;
document.cookie = cookieString;
};
3.获取两个日期间隔多少天
/**
* @description 计算两个日期之间相差的天数
* @param {Date | string | number} date1 第一个日期
* @param {Date | string | number} date2 第二个日期
* @param {boolean} absolute 是否返回绝对值,默认true
* @returns 相差的天数
*/
export const getDaysDifference = (date1: Date | string | number, date2: Date | string | number, absolute = true): number => {
const d1 = new Date(date1);
const d2 = new Date(date2);
if (isNaN(d1.getTime()) || isNaN(d2.getTime())) {
throw new Error('Invalid date provided');
}
const timeDiff = d2.getTime() - d1.getTime();
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
return absolute ? Math.abs(daysDiff) : daysDiff;
};
4.获取url地址上的参数值
/**
* @description 获取URL参数值
* @param {string} paramName 参数名,不传则返回所有参数
* @param {string} url 目标URL,不传则使用当前页面URL
* @returns {string | Record<string, string> | null} 指定参数值或所有参数对象
*/
export const getUrlParams = (paramName?: string, url?: string): string | Record<string, string> | null => {
if (!url && typeof window === 'undefined') return null;
const targetUrl = url || window.location.href;
// 提取查询字符串部分
const queryIndex = targetUrl.indexOf('?');
if (queryIndex === -1) {
return paramName ? null : {};
}
const queryString = targetUrl.substring(queryIndex + 1);
if (!queryString) {
return paramName ? null : {};
}
// 解析查询参数
const params: Record<string, string> = {};
const pairs = queryString.split('&');
for (const pair of pairs) {
const equalIndex = pair.indexOf('=');
if (equalIndex === -1) {
// 没有值的参数,如 ?flag
const key = decodeURIComponent(pair);
params[key] = '';
} else {
const key = decodeURIComponent(pair.substring(0, equalIndex));
const value = decodeURIComponent(pair.substring(equalIndex + 1));
params[key] = value;
}
}
// 如果指定了参数名,返回对应值
if (paramName) {
return params[paramName] || null;
}
// 返回所有参数
return params;
};
5.数组去重
/**
* @description 数组对象根据指定key的值做去重
* @param {T[]} array 目标数组
* @param {K} key 去重的key
* @returns {T[]} 去重后的数组
*/
export const uniqueByKey = <T extends Record<string, string | number | null | undefined>, K extends keyof T>(array: T[], key: K): T[] => {
if (!Array.isArray(array) || array.length === 0) {
return [];
}
const seen = new Set();
return array.filter((item) => {
const value = item[key];
if (seen.has(value)) {
return false;
}
seen.add(value);
return true;
});
};
6.数组排序
/**
* @description 数组对象根据指定key的值做排序
* @param {T[]} array 目标数组
* @param {K} key 排序的key
* @param {'asc' | 'desc'} order 排序方式,'asc'为正序,'desc'为倒序,默认'asc'
* @returns {T[]} 排序后的数组
*/
export const sortByKey = <T extends Record<string, string | number | null | undefined>, K extends keyof T>(
array: T[],
key: K,
order: 'asc' | 'desc' = 'asc',
): T[] => {
if (!Array.isArray(array) || array.length === 0) {
return [];
}
return [...array].sort((a, b) => {
const aValue = a[key];
const bValue = b[key];
// 处理null/undefined值
if (aValue == null && bValue == null) return 0;
if (aValue == null) return order === 'asc' ? -1 : 1;
if (bValue == null) return order === 'asc' ? 1 : -1;
// 数字类型比较
if (typeof aValue === 'number' && typeof bValue === 'number') {
return order === 'asc' ? aValue - bValue : bValue - aValue;
}
// 字符串类型比较
if (typeof aValue === 'string' && typeof bValue === 'string') {
return order === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
}
// 其他情况转换为字符串比较
const aStr = String(aValue);
const bStr = String(bValue);
return order === 'asc' ? aStr.localeCompare(bStr) : bStr.localeCompare(aStr);
});
};
7.树接口平铺
/**
* @description 树结构转换配置
*/
interface TreeConfig<T, R = T> {
/** 父级ID字段名 */
parentId: keyof T;
/** 自身ID字段名 */
id: keyof T;
/** 子节点字段名 */
children: keyof T;
/** 格式化函数,用于处理每个节点 */
format?: (item: T) => R;
}
/**
* @description 将树结构数组平铺为一维数组
* @param {T[]} treeList 树结构数组
* @param {TreeConfig<T>} config 配置项
* @returns {R[]} 平铺后的一维数组
*/
export const flattenTree = <T extends Record<string, any>, R = T>(treeList: T[], config: TreeConfig<T, R>): R[] => {
if (!Array.isArray(treeList) || treeList.length === 0) {
return [];
}
const { children, format } = config;
const result: R[] = [];
const traverse = (nodes: T[]) => {
for (const node of nodes) {
// 处理当前节点
const processedNode = format ? format(node) : (node as unknown as R);
result.push(processedNode);
// 递归处理子节点
const childNodes = node[children];
if (Array.isArray(childNodes) && childNodes.length > 0) {
traverse(childNodes);
}
}
};
traverse(treeList);
return result;
};
8.一级list列表转为树结构列表
/**
* @description 将平铺的一维数组转换为树结构
* @param {T[]} flatList 平铺的一维数组
* @param {TreeConfig<T>} config 配置项
* @returns {any[]} 树结构数组
*/
export const buildTree = <T extends Record<string, any>, R = T>(flatList: T[], config: TreeConfig<T, R>): R[] => {
if (!Array.isArray(flatList) || flatList.length === 0) {
return [];
}
const { parentId, id, children, format } = config;
const map = new Map<any, R>();
const roots: R[] = [];
// 创建节点映射
for (const item of flatList) {
const processedItem = format ? format(item) : (item as unknown as R);
const nodeId = item[id];
const nodeParentId = item[parentId];
// 初始化节点
if (!map.has(nodeId)) {
const newNode = { ...processedItem, [children]: [] } as R;
map.set(nodeId, newNode);
} else {
// 合并已存在的节点
const existingNode = map.get(nodeId);
if (!existingNode) continue;
const mergedNode = { ...existingNode, ...processedItem } as R;
map.set(nodeId, mergedNode);
}
const node = map.get(nodeId);
if (!node) continue;
// 处理父子关系
if (nodeParentId == null || nodeParentId === '' || nodeParentId === 0) {
// 根节点
roots.push(node);
} else {
// 子节点
if (!map.has(nodeParentId)) {
const parentNode = { [children]: [] } as R;
map.set(nodeParentId, parentNode);
}
const parentNode = map.get(nodeParentId);
if (!parentNode) continue;
(parentNode as any)[children].push(node);
}
}
return roots;
};
9.单位换算
/**
* @description 单位区间配置接口
*/
interface UnitRange {
/** 最小值(包含) */
min: number;
/** 最大值(不包含) */
max: number;
/** 单位 */
unit: string;
/** 除数,用于转换数值 */
divisor: number;
/** 小数位数 */
decimals?: number;
}
/**
* @description 单位转换结果接口
*/
interface UnitConvertResult {
/** 原始值 */
originalValue: number;
/** 转换后的单位 */
unit: string;
/** 转换后的数值 */
convertedValue: number;
}
/**
* @description 单位转换函数
* @param {number} value 数值
* @param {UnitRange[]} unitRanges 单位对应数值区间配置
* @param {string} defaultUnit 默认单位
* @returns {UnitConvertResult} 转换结果
*/
export const convertUnit = (value: number, unitRanges: UnitRange[], defaultUnit: string): UnitConvertResult => {
if (!Array.isArray(unitRanges) || unitRanges.length === 0) {
throw new Error('unitRanges must be a non-empty array');
}
const absValue = Math.abs(value);
const sign = value < 0 ? -1 : 1;
// 查找匹配的单位区间
let matchedRange: UnitRange | null = null;
for (const range of unitRanges) {
if (absValue >= range.min && absValue < range.max) {
matchedRange = range;
break;
}
}
// 如果没有找到匹配的区间,使用默认单位
if (!matchedRange) {
return {
originalValue: value,
unit: defaultUnit,
convertedValue: value,
};
}
// 计算转换后的数值
const convertedAbsValue = absValue / matchedRange.divisor;
const decimals = matchedRange.decimals ?? 2;
const formattedValue = Number(convertedAbsValue.toFixed(decimals));
const finalValue = formattedValue * sign;
return {
originalValue: value,
unit: matchedRange.unit,
convertedValue: finalValue,
};
};
// 示例
const storageRanges: UnitRange[] = [
{ min: 0, max: 1024, unit: 'B', divisor: 1, decimals: 0 },
{ min: 1024, max: 1048576, unit: 'KB', divisor: 1024, decimals: 1 },
{ min: 1048576, max: 1073741824, unit: 'MB', divisor: 1048576, decimals: 2 },
{ min: 1073741824, max: Infinity, unit: 'GB', divisor: 1073741824, decimals: 2 }
];
console.log(convertUnit(512, storageRanges, 'B'));
// { originalValue: 512, unit: 'B', convertedValue: 512 }
console.log(convertUnit(2048, storageRanges, 'B'));
// { originalValue: 2048, unit: 'KB', convertedValue: 2 }
console.log(convertUnit(5242880, storageRanges, 'B'));
// { originalValue: 5242880, unit: 'MB', convertedValue: 5 }