工具库 blog.csdn.net/frontlab/ar…
算术运算(也可以引入decimal.js库)
- 手动实现 src/utils/math.js
/**
* @desc 获取小数位数
* @param {value} 数字
*/
function getDecimalPlaces(value) {
if (Math.floor(value) !== value) {
return value?.toString().split('.')[1]?.length ?? 0;
}
return 0;
}
/**
* @desc 加减运算
* @param {a}
* @param {b}
* @param {decimalPlaces} 需要保留几位小数
* @param {operator} '+' '-'
* @return {res} 计算结果
*/
function addOrSubtract(a, b, decimalPlaces, operator) {
const maxDecimalPlaces = Math.max(getDecimalPlaces(a), getDecimalPlaces(b));
const factor = Math.pow(10, maxDecimalPlaces);
let result;
if (operator === '+') {
result = (a * factor + b * factor) / factor;
} else {
result = (a * factor - b * factor) / factor;
}
return result.toFixed(decimalPlaces ?? maxDecimalPlaces);
}
/**
* @desc 加运算
* @param {a}
* @param {b}
* @param {decimalPlaces} 需要保留几位小数
* @return {res} 计算结果
*/
export function add(a, b, decimalPlaces) {
return addOrSubtract(a, b, decimalPlaces, '+');
}
/**
* @desc 减运算
* @param {a}
* @param {b}
* @param {decimalPlaces} 需要保留几位小数
* @return {res} 计算结果
*/
export function subtract(a, b, decimalPlaces) {
return addOrSubtract(a, b, decimalPlaces, '-');
}
/**
* @desc 乘法运算
* @param {a}
* @param {b}
* @param {decimalPlaces} 需要保留几位小数
* @return {res} 计算结果
*/
export function multiply(a, b, decimalPlaces) {
const maxDecimalPlaces = Math.max(getDecimalPlaces(a), getDecimalPlaces(b));
const factor = Math.pow(10, getDecimalPlaces(a) + getDecimalPlaces(b));
return ((a * factor * (b * factor)) / (factor * factor)).toFixed(decimalPlaces ?? maxDecimalPlaces);
}
/**
* @desc 除法运算
* @param {a}
* @param {b}
* @param {decimalPlaces} 需要保留几位小数
* @return {res} 计算结果
*/
export function divide(a, b, decimalPlaces) {
if (b !== 0) {
const maxDecimalPlaces = Math.max(getDecimalPlaces(a), getDecimalPlaces(b));
const factor = Math.pow(10, getDecimalPlaces(b) - getDecimalPlaces(a));
return ((a * factor) / (b * factor)).toFixed(decimalPlaces ?? maxDecimalPlaces);
} else {
throw new Error('Division by zero is not allowed.');
}
}
console.log(add(1, 3));
console.log(add(1.12, 0.03));
console.log(subtract(5, 1));
console.log(subtract(2.2, 0.0212));
console.log(multiply(5, 6));
console.log(multiply(5.05, 1.0332));
console.log(divide(9, 6));
console.log(divide(8.32, 2.2, 2));
- decimal.js
npm install --save decimal.js // 安装
import { Decimal } from "decimal.js" // 引入
const a = 9.99;
const b = 8.03;
let c = new Decimal(a).add(new Decimal(b)).sub(new Decimal(5) ).mul(new Decimal(2)).div(new Decimal(1))
// c 是 Decimal 对象,你可以使用 .toNumber() .toString() 转换成对应数字 字符串类型
console.log(c.toNumber());
格式器 src/utils/formatter.js
/**
* @desc to千分位
* @param {number} 需要处理的数字
* @return {result} 千分位
*/
export function toThousands(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
/**
* @desc to百分比
* @param {number} 需要处理的数字
* @param {decimalPlaces} 小数点后需要保留的位数
* @return {result} 千分位
*/
export function toPercentage(number, decimalPlaces = 2) {
const percentage = (number * 100).toFixed(decimalPlaces);
return `${percentage}%`;
}
/**
* @desc 手机号格式化 XXXXXXXXXXX ===>>> XXX XXXX XXXX
* @param {phoneNumber}
* @return {result}
*/
export function formatMobileNumber(phoneNumber) {
// 移除所有非数字字符
const cleanPhoneNumber = phoneNumber.replace(/\D/g, '');
return cleanPhoneNumber.replace(/(\d{3})(\d{4})(\d{4})/, '$1 $2 $3');
}
/**
* @desc 格式化地区信息
* @param {String} str 要格式化的地区信息
* @returns Object {province: "", city: "", detail: ""}
*/
export function formatAddress(str = '') {
const result = {
province: '',
city: '',
detail: '',
};
const provinceRegExp = /(.+?(省|自治区))(.*)/;
const provinceList = str.match(provinceRegExp);
let restStr = str;
if (provinceList) {
result.province = provinceList[1];
restStr = provinceList[3];
}
const cityRegExp = /(.+?(市|自治州|行政区))(.*)/;
const cityList = restStr.match(cityRegExp);
if (cityList) {
result.city = cityList[1];
result.detail = cityList[3];
} else {
result.detail = restStr;
}
return result;
}
/**
* @desc 格式化文件大小
* @param {bytes} 大小
* @param {decimalPlaces} 小数点后需要保留的位数
* @return {result}
*/
export function formatFileSize(bytes, decimalPlaces = 2) {
if (bytes === 0) return '0 Bytes';
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return `${(bytes / Math.pow(1024, i)).toFixed(decimalPlaces ?? 2)} ${sizes[i]}`;
}
/**
* @desc 格式化文件大小
* @param {size}
* @param {unit} 转化后的单位
* @param {decimalPlaces} 小数点后需要保留的位数
* @return {result}
*/
export function formatFileSizeByUnit(size, unit = 'MB', decimalPlaces = 2) {
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const unitIndex = sizes.indexOf(unit.toUpperCase());
if (unitIndex === -1) {
throw new Error('Invalid unit. Available units: B, KB, MB, GB, TB');
}
const formattedSize = size / Math.pow(1024, unitIndex);
return `${formattedSize.toFixed(decimalPlaces ?? 2)} ${unit}`;
}
console.log(toThousands(1234589.56)); // 1,234,589.56
console.log(toPercentage(0.23)); // 23.00%
console.log(formatMobileNumber('18817471234'));// 188 1747 1234
console.log(formatAddress("广西壮族自治区南宁市西乡塘区XX街XX号")); // {province: '广西壮族自治区', city: '南宁市', detail: '西乡塘区XX街XX号'}
console.log(formatAddress("上海市浦东新区xxx路xxx号")); // {province: '', city: '上海市', detail: '浦东新区xxx路xxx号'}
console.log(formatFileSize(1234565)); // 1.18 MB
console.log(formatFileSizeByUnit(1234565, 'KB')); // 1205.63 KB
日期辅助类 src/utils/dateHelper.js(在dayjs基础上实现)
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween'; // 引入相关插件
dayjs.extend(isBetween);
// 封装一个日期工具类
export class DateHelper {
/**
* @desc 初始化
* @param {dateString} 日期字符串 或者 日期对象
*/
constructor(dateString) {
this.date = dayjs(dateString);
}
/**
* @desc 格式化时间
* @param {formatString} YYYY年M月D日 YYYY-MM-DD HH:mm:ss
* @return {str} 格式化后的时间
*/
format(formatString) {
return this.date.format(formatString);
}
/**
* @desc 加
* @param {num}
* @param {unit} millisecond second minute hour day week month year
* @param {formatString}
* @return {}
*/
add(num, unit = 'day', formatString = 'YYYY-MM-DD') {
return this.date.add(num, unit).format(formatString);
}
/**
* @desc 减
* @param {num}
* @param {unit} millisecond second minute hour day week month year
* @param {formatString}
* @return {}
*/
subtract(num, unit = 'day', formatString = 'YYYY-MM-DD') {
return this.date.subtract(num, unit).format(formatString);
}
/**
* @desc 获取某年(某月)的第一天
* @param {unit} month:某月 year:某年
* @param {formatString} month:某月 year:某年
* @return {}
*/
getFirstDayByUnit(unit = 'month', formatString = 'YYYY-MM-DD') {
return this.date.startOf(unit).format(formatString);
}
/**
* @desc 获取某年(某月)的最后一天
* @param {unit} month:某月 year:某年
* @param {formatString} month:某月 year:某年
* @return {}
*/
getLastDayByUnit(unit = 'month', formatString = 'YYYY-MM-DD') {
return this.date.endOf(unit).format(formatString);
}
/**
* @desc 获取时间差
* @param {otherDate}
* @param {unit}
* @return {}
*/
getDiff(otherDate, unit = 'day') {
return this.date.diff(otherDate, unit);
}
/**
* @desc 判断一个日期是否在另外一个日期之后
* @param {otherDate}
* @return {} true:之后 false:之前
*/
isAfter(otherDate) {
return this.date.isAfter(otherDate);
}
/**
* @desc 判断一个日期是否在另外一个日期之前
* @param {otherDate}
* @return {} true:之前 false:之后
*/
isBefore(otherDate) {
return this.date.isBefore(otherDate);
}
/**
* @desc 判断一个日期是否在两个日期之间
* @param {a}
* @param {b}
* @return {} true:是
*/
isBetween(a, b) {
return this.date.isBetween(a, b);
}
}
const customDate = new DateHelper(new Date()); // 2023年8月31日
console.log(customDate.format('YYYY年M月D日')); // 2023-08-31
console.log(customDate.format('MM/DD HH:mm:ss')); // 08/31 15:33:55
console.log(customDate.add(3, 'day')); // 2023-09-03
console.log(new DateHelper(new Date()).getFirstDayByUnit()); // 2023-08-01
console.log(new DateHelper('2022-09').getLastDayByUnit()); // 2022-09-30
console.log(new DateHelper(new Date()).isAfter('2023-08-31 10:59:59')); // true
console.log(new DateHelper(new Date()).isBetween('2023-09-01 10:59:59', '2023-09-07 10:59:59')); // false
脱敏辅助类 src/utils/desensitizerHelper.js
export class DesensitizerHelper {
// 姓名脱敏
static desensitizeName(name) {
if (name.length === 1) {
return name;
}
return `${name[0]}${'*'.repeat(name.length - 1)}`;
}
// 手机号脱敏
static desensitizePhoneNumber(phoneNumber) {
return phoneNumber.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
// 邮箱脱敏
static desensitizeEmail(email) {
const [username, domain] = email.split('@');
const usernameLen = username.length;
const maskedUsername = usernameLen <= 2 ? '*'.repeat(usernameLen) : `${username[0]}*${username[usernameLen - 1]}`;
return `${maskedUsername}@${domain}`;
}
// 银行卡号脱敏
static desensitizeBankCardNumber(cardNumber) {
const visibleDigits = 4; // 可见的末尾几位数字
const maskedDigits = cardNumber.length - visibleDigits;
const maskedPart = '*'.repeat(maskedDigits);
const visiblePart = cardNumber.slice(maskedDigits);
return maskedPart + visiblePart;
}
// 身份证号脱敏
static desensitizeIDNumber(idNumber) {
return idNumber.replace(/(\d{4})\d+(\d{4})/, '$1****$2');
}
// 护照脱敏
static desensitizePassportNumber(passportNumber) {
return passportNumber.replace(/(.{2}).+(.{2})/, '$1****$2');
}
// 座机号脱敏
static desensitizeLandlinePhoneNumber(landline) {
return landline.replace(/(\d{3}-\d{4})(\d+)/, '$1****$2');
}
// 地址脱敏
static desensitizeAddress(address) {
const visiblePart = address.substring(0, 6);
const maskedPart = '*'.repeat(address.length - visiblePart.length);
return visiblePart + maskedPart;
}
}
校验器 src/utils/validators
const patterns = {
nameCn: /^[\u4e00-\u9fa5]{2,4}$/, // 2-4个汉字,用于验证中文姓名
nameEn: /^[A-Za-z]+([-']?[A-Za-z]+)?\s[A-Za-z]+([-']?[A-Za-z]+)?$/, //英文姓名可以包含字母、空格、连字符(-)和撇号(')等符号
mobile: /^(13[0-9]|14[5-9]|15[0-3,5-9]|16[5,6]|17[0-8]|18[0-9]|19[1,8,9])\d{8}$/, // 用于验证手机号码
email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, //用于验证电子邮箱
chinese: /[\u4e00-\u9fa5]/, //匹配所有汉字
geZeroInt: /^\d+$/, // 用于验证大于或等于0的整数
int: /^-?\d+$/, // 用于验证整数,包括正整数、负整数和0
geZero: /^\d+(\.\d+)?$/, // 用于验证大于或等于0的数字,可以是整数或小数
idNo: /^\d{17}(\d|x)$/,// 用于验证身份证号码,支持18位身份证和17位身份证+x
qqNo: /^[1-9]\d{4,10}$/, // 用于验证QQ号码,5-11位数字,第一位不能是0
weNo: /^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/, // 用于验证微信号码,6-20位字符,以字母开头,允许使用数字、字母、下划线和中划线
carNo: /^[\u4e00-\u9fa5]{1}[A-Z]{1}[A-Z_0-9]{5}$/, // 用于验证车牌号码,车牌号格式为汉字 + 大写字母 + 5位数字或字母
creditCode: /^[0-9A-Z]{18}$/, // 用于验证统一社会信用代码,18位数字
}
const validators = {}
/**
* @desc 生成各种类别校验器 使用方式:validateNameCn("王xx") validateMobile('18817761234')
*/
for (const key of Object.keys(patterns)) {
const PascalCaseKey = key.slice(0, 1).toUpperCase() + key.slice(1)
validators[`validate${PascalCaseKey}`] = (val) => patterns[key].test(val)
}
export { validators };
lodash辅助器 src/utils/lodashHelper
import debounce from 'lodash/debounce'
import cloneDeep from 'lodash/cloneDeep'
export class LodashHelper {
static cloneDeep(obj) {
return cloneDeep(obj);
}
static throttle(func, wait, options) {
return throttle(func, wait, options);
}
static debounce(func, wait, options) {
return debounce(func, wait, options);
}
}
字符串操作 src/utils/character
/**
* @desc 随机字符串
* @param {length} 指定长度
* @param {characters} 限定字符串范围
* @return {}
*/
export function generateRandomString(length = 20, characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
let result = '';
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
result += characters[randomIndex];
}
return result;
}
文件下载 src/utils/downloadFile
/**
* @desc 将 url 转化成对应的文件并下载
* @param {url}
* @param {fileName}
* @return {}
*/
export function downloadFileByURL(url, fileName) {
const aEle = document.createElement('a')
aEle.setAttribute('href', url)
fileName = decodeURIComponent(fileName)
aEle.setAttribute('download', fileName)
document.body.appendChild(aEle)
aEle.click()
document.body.removeChild(aEle)
}
/**
* @desc 将 blob 转化成对应的文件并下载
* @param {blob}
* @param {mimeType} image/png application/pdf https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
* @param {fileName} 文件名称 不带后缀
* @return {}
*/
export function downloadFileByBlob(blob, mimeType, fileName) {
const url = window.URL.createObjectURL(new Blob([blob], { type: mimeType }))
downloadFileByURL(url, fileName)
}
const content = 'Hello, World!';
downloadFileByBlob(content, 'text/plain', 'test');