常用工具方法总结。
千分位
export const comdify = (n) => {
// 千分制
n = '' + n;
let isMinus = false;
if (n.startsWith('-')) {
isMinus = true;
n = n.slice(1);
}
const re = /\d{1,3}(?=(\d{3})+$)/g;
const n1 = n.replace(/^(\d+)((\.\d+)?)$/, function (s, s1, s2) {
return s1.replace(re, '$&,') + s2;
});
return isMinus ? '-' + n1 : n1;
};
正则校验
// 常用正则验证
const checkStr = (str, type) => {
switch (type) {
case 'phone': //手机号码
return /^1\d{10}$/.test(str);
case 'tel': // 座机
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
case 'card': // 身份证
return /^\d{15}|\d{18}$/.test(str);
case 'pwd': // 密码以字母开头,长度在6~18之间,只能包含字母、数字和下划线
return /^[a-zA-Z]\w{5,17}$/.test(str);
case 'postal': // 邮政编码
return /[1-9]\d{5}(?!\d)/.test(str);
case 'QQ': // QQ号 5-11位数字
return /^[1-9]\d{4,10}$/.test(str);
case 'email': // 邮箱
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'money': // 金额(小数点2位)
return /^\d*(?:\.\d{0,2})?$/.test(str);
case 'URL': // 网址
return /(https?|ftp):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(
str
);
case 'IP': // IP
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(
str
);
case 'day': // 一个月的31天 01-09和1~31
return /^((0?[1-9])|(([12])[0-9])|30|31)$/.test(str);
case 'month': // 一年的12个月 01-09和1-12
return /^(0?[1-9]|1[0-2])$/.test(str);
case 'date': // 日期时间
return (
/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(
str
) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(str)
);
case 'poInteger': // 整数 正整数
return /^\d+$/.test(str);
case 'integer': // 整数 正整数或负整数
return /^-?\d+$/.test(str);
case 'decimal': // 小数
return /^(-?\d+)(\.\d+)?$/.test(str);
case 'english': // 英文
return /^[a-zA-Z]+$/.test(str);
case 'chinese': // 中文
return /^[\u4E00-\u9FA5]+$/.test(str);
case 'cname': // 中文姓名 2-4位汉字
return /^[\u4E00-\u9FA5]{2,4}$/.test(str);
case 'lower': // 小写
return /^[a-z]+$/.test(str);
case 'upper': // 大写
return /^[A-Z]+$/.test(str);
case 'HTML': // HTML标记
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
default:
throw new Error('检验出错 in function checkStr');
}
};
校验是否为中国大陆手机号
// 说明:现在已经出现了16开头的手机号,原正则`/^1[3,4,5,7,8][0-9]{9}$/`不再适用
function isTel(value) {
return /^1[3,4,5,6,7,8,9][0-9]{9}$/.test(value.toString());
}
数据统计处理
// 去除字符串两边的空格 trim
String.prototype.trim = function() {
return this.replace(/(^\s+)\|(\s+$)/g, '')
}
// 找出重复最多的字符
let str = 'asss23sjdssskssa7lsssdkjsssdss'
const repeatMost = (str) => {
const arr = str.split(/\s*/) // 把字符串转换为数组
const str2 = arr.sort().join('') // 首先进行排序,这样结果会把相同的字符放在一起,然后再转换为字符串
let value = ''
let index = 0
str2.replace(/(\w)\1*/g, function($0, $1) { // 匹配字符
if (index < $0.length) {
index = $0.length // index是出现次数
value = $1 // value是对应字符
}
})
console.log(`最多的字符: ${value} ,重复的次数: ${index}`)
}
repeatMost(str)
// 数字格式化,1234567890 -> 1,234,567,890
const numFormat = str => str.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
// 手机号中间四位换*
const validateMobile = str => /^[1][0-9]{10}$/.test(str) && str.replace(/(\d{3})(\d{4})(\d{4})/, (rs, $1, $2, $3) => `${$1}****${$3}`)
// 取URL中query到一个对象中
function getUrlParam(str) {
const result = {}
const valid = /(https?|ftp):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.exec(str)
if (!valid) return
const [rs, $1, $2, $3] = valid
$3.match(/[a-zA-Z_]+=[^=&?]*/g).forEach(val => val.replace(/^(\w+)=(\w*)$/, ($0, $1, $2) => {
result[$1] = $2
})
)
return result
}
getUrlParam('https://www.baidu.com?name=jawil&age=23&d=') // {name: "jawil", age: "23", d: ""}
// 验证是否是合法URL
function validateURL(textval) {
const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return urlregex.test(textval)
}
// HTML编码,对< / > " & \等字符转义,避免XSS攻击
function htmlEncode(str) {
return str.replace(/[\<\>\"\'\&]/g, function(rs) {
switch (rs) {
case '<':
return '<'
case '>':
return '>'
case '&':
return '&'
case ''':
return '''
case '"':
return '"'
}
})
}
Cookie 的 CRUD
// 批量写cookies
export const setCookieByBatch = (
cookiesObj: {
[key: string]: any;
},
days?: number
) => {
let expires = 'Session';
if (days) {
const exp = new Date();
exp.setTime(exp.getTime() + days * 86400000);
expires = exp.toUTCString();
}
for (const key in cookiesObj) {
// 同一个域内 cookie 是按名称来存储和检索的,不同名就不会出现被覆盖的情况
// 使用escape编码,使用decodeURIComponent解码在中文情况下可能会报URI的错误
document.cookie = `${key}=${encodeURIComponent(
cookiesObj[key]
)};expires=${expires}`;
}
};
// 获取所有cookies
export const getAllCookie = () => {
const cookies = document.cookie.split(/;\s*/);
const jsonCookies = {};
for (const item of cookies) {
// 将每条数据以=号拆开
const data = item.split('=');
// 数组中的第一元素为属性名 第二一个为值【第二个为对象类型时,还需要继续decodeURIComponent,这里只做一层】
jsonCookies[data[0]] = decodeURIComponent(data[1]);
}
return jsonCookies;
};
// 获取指定cookies
export const getCookie = (name: string) => {
let arr;
const reg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
// eslint-disable-next-line no-cond-assign
if ((arr = reg.exec(document.cookie))) {
return decodeURIComponent(arr[2]);
} else {
return null;
}
};
// 具体的删除cookie逻辑
const realDelCookie = (name: string, expires: any) => {
const cval = getCookie(name);
if (cval) {
document.cookie = `${name}=${cval};expires=${expires.toUTCString()}`;
}
};
/**
* 删除cookie,支持批量
* @param name
*/
export const delCookie = (name: string | string[]) => {
const exp = new Date();
exp.setTime(exp.getTime() - 1);
if (Array.isArray(name)) {
for (const item of name) {
realDelCookie(item, exp);
}
} else {
realDelCookie(name, exp);
}
};
Storage 的 CRUD
const Store = {
// 存储localstorage时候最好是封装一个自己的键值,在这个值里存储自己的内容对象,封装一个方法针对自己对象进行操作。避免冲突也会在开发中更方便。
ns: 'letschat_web_storage',
init: (ns = 'letschat_web_storage') => {
const mydata = localStorage.getItem(ns);
if (mydata) {
return;
}
Store.ns = ns;
localStorage.setItem(ns, '{"data":{}}');
},
// 检测浏览器是否支持localStorage
check: () => {
return Boolean(window.localStorage);
},
// 读取
get: (key: string) => {
let mydata = localStorage.getItem(Store.ns);
if (!mydata) {
return null;
}
mydata = JSON.parse(mydata);
// @ts-expect-error
return mydata.data[key];
},
// 存储
set: (key: string, value: any) => {
const { ns } = Store;
let mydata = localStorage.getItem(Store.ns);
if (!mydata) {
Store.init();
mydata = localStorage.getItem(ns);
}
mydata = JSON.parse(mydata as string);
// @ts-expect-error
mydata.data[key] = value;
localStorage.setItem(ns, JSON.stringify(mydata));
},
remove: (key: string) => {
// 读取
let mydata = localStorage.getItem(Store.ns);
if (!mydata) {
return false;
}
mydata = JSON.parse(mydata);
// @ts-expect-error
mydata.data[key] = null;
localStorage.setItem(Store.ns, JSON.stringify(mydata));
return true;
},
clear: () => {
// 清除对象
localStorage.removeItem(Store.ns);
},
// 批量保存,data是一个字典
setList: (data: { [key: string]: any }) => {
for (const i in data) {
Store.set(i, data[i]);
}
},
// 批量删除,list是一个数组
removeList: (list: string[]) => {
for (let i = 0, len = list.length; i < len; i++) {
Store.remove(list[i]);
}
},
};
删除 URL 中某个参数
// 删除url中某个参数
export const delUrlSearch = (name: string) => {
let baseUrl = '';
let url = location.href;
if (url.includes('&')) {
baseUrl = url.split('?')[0] + '?';
} else {
baseUrl = url.split('?')[0];
}
const query = url.split('?')[1];
if (query?.includes(name)) {
const obj = {};
const arr: any = query.split('&');
for (let i = 0; i < arr.length; i++) {
const temp = arr[i].split('=');
obj[temp[0]] = temp[1];
}
delete obj[name];
url =
baseUrl +
JSON.stringify(obj)
.replace(/[\"\{\}]/g, '')
.replace(/\:/g, '=')
.replace(/\,/g, '&');
}
window.history.pushState({}, '', url);
};
简单的加密:字符串生成 base64
// 可用atob解密
export const Base64Handle = {
// private property
_keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
// public method for encoding
encode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
input = Base64Handle._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output =
output +
this._keyStr.charAt(enc1) +
this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) +
this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output += String.fromCharCode(chr1);
if (enc3 != 64) {
output += String.fromCharCode(chr2);
}
if (enc4 != 64) {
output += String.fromCharCode(chr3);
}
}
output = Base64Handle._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode(string) {
string = string.replace(/\r\n/g, '\n');
let utftext = '';
for (let n = 0; n < string.length; n++) {
const c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode(utftext) {
let string = '';
let i = 0;
let c = (c1 = c2 = 0);
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if (c > 191 && c < 224) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(
((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)
);
i += 3;
}
}
return string;
},
};
请求接口缓存
class ItemCache {
constructor(data, timeout) {
this.data = data;
// 设定超时时间,设定为多少秒
this.timeout = timeout;
// 创建对象时候的时间,大约设定为数据获得的时间
this.cacheTime = new Date().getTime();
}
}
class ExpiresCache {
// 定义静态数据map来作为缓存池
static cacheMap = new Map();
// 数据是否超时
static isOverTime(name) {
const data = ExpiresCache.cacheMap.get(name);
// 没有数据 一定超时
if (!data) return true;
// 获取系统当前时间戳
const currentTime = new Date().getTime();
// 获取当前时间与存储时间的过去的秒数
const overTime = (currentTime - data.cacheTime) / 1000;
// 如果过去的秒数大于当前的超时时间,也返回null让其去服务端取数据
if (Math.abs(overTime) > data.timeout) {
// 此代码可以没有,不会出现问题,但是如果有此代码,再次进入该方法就可以减少判断。
ExpiresCache.cacheMap.delete(name);
return true;
}
// 不超时
return false;
}
// 当前data在 cache 中是否超时
static has(name) {
return !ExpiresCache.isOverTime(name);
}
// 删除 cache 中的 data
static delete(name) {
return ExpiresCache.cacheMap.delete(name);
}
// 获取
static get(name) {
const isDataOverTime = ExpiresCache.isOverTime(name);
//如果 数据超时,返回null,但是没有超时,返回数据,而不是 ItemCache 对象
return isDataOverTime ? null : ExpiresCache.cacheMap.get(name).data;
}
static set(name, data, timeout) {
// 设置 itemCache
const itemCache = new ItemCache(data, timeout);
//缓存
ExpiresCache.cacheMap.set(name, itemCache);
}
}
// 生成key值错误
const generateKeyError = new Error("Can't generate key from name and argument");
// 生成key值
function generateKey(name, params) {
try {
// 返回 字符串,函数名 + 函数参数
return `${name}:${JSON.stringify(params)}`;
} catch (_) {
// 返回生成key错误
return generateKeyError;
}
}
// 使用时调用cachePostRequest这个方法,默认存储30分钟
export const cachePostRequest = async (
path: string,
params: { [key: string]: any },
timeout = 1800
) => {
// 生成key
const key = generateKey(path, params);
// 获得数据
let data = ExpiresCache.get(key);
if (!data) {
data = await request(path, params);
// 使用 30min 缓存,30min之后再次get就会 获取null 而从服务端继续请求
const { status_code } = data;
// 保证请求成功再缓存,status_code字段需要根据后端约定自行更换key值
status_code === 200 && ExpiresCache.set(key, data, timeout);
}
return data;
};