一、数字
1、数字格式化
数字千分位逗号分隔:new Intl.NumberFormat().format(num)
const formatNumber = (num)=> new Intl.NumberFormat().format(num);console.log([formatNumber("12345"),formatNumber(12345)])//["12,345", "12,345"]
货币化:new Intl.NumberFormat(‘zh-CN’,{ style: ‘currency’, currency: ‘CNY’,maximumFractionDigits: maxDig }).format(num)
常见方法
// 格式化货币const formatMoney = (value, type = 2) => {let s = value < 0 ? Math.abs(value) : value;if (/[^0-9.]/.test(s)) return '¥ 0.00';if (s === null || s === 'null' || s === '') return '¥ 0.00';s = s.toString().replace(/^(\d*)$/, '$1.');s = (s + '00').replace(/(\d*\.\d\d)\d*/, '$1');s = s.replace('.', ',');var re = /(\d)(\d{3},)/;while (re.test(s)) s = s.replace(re, '$1,$2');s = s.replace(/,(\d\d)$/, '.$1');if (type === 0) {var a = s.split('.');if (a[1] === '00') {s = a[0];}}return value < 0 ? '¥ -' + s : '¥ ' + s;};console.log(formatMoney(12345.6789))//¥ 12,345.67
新方法 ```typescript // 格式化货币 const formatCurrency = (num, maxDig = 6) => { const currency = ‘CNY’; const locale = ‘zh-CN’;
if ( (typeof num === ‘string’ && [‘null’, ‘undefined’, ‘’].includes(num.trim())) || (typeof num !== ‘string’ && isNaN(num)) ) { return ‘¥ 0’; } else { try {
const formatVal = new Intl.NumberFormat(locale, {style: 'currency',currency,...(maxDig ? { maximumFractionDigits: maxDig } : {}),}).format(parseFloat(String(num)));return formatVal || '¥ 0';
} catch (err) {
return '¥ 0';
} } };
- 大数据量统计```javascriptconst nums = [1234, 123456.789, 123456789123, 123456789123456,123456789123456789]nums.map(num => {return new Intl.NumberFormat('zh-CN', { notation: "compact" }).format(num)})//["1234", "12万", "1235亿", "123万亿", "123,457万亿"]
- 百分比展示 ```javascript [0.01, 1.2, 0.0123].map(num => { return new Intl.NumberFormat(undefined, { style: ‘percent’, maximumFractionDigits: 2 }).format(num) }) // [“1%”, “120%”, “1.23%”]
<a name="lWZxg"></a>### 2、数字校验```javascript// 是否是数字// 1、js方法const isNumber = value => !isNaN(parseFloat(value)) && isFinite(value);// 2、正则const isNumberRegex = value=> /^\d{1,}$/.test(value)// 是否是正数// 1、js方法const isPositive = value => isNumber(value) && Math.sign(value) === 1;// 2、正则判断正浮点数const isPositiveFloat = value => Math.sign(Number(value ?? 0) || 0) === 1 && /^(?:[1-9]\d*|0)?(?:\.\d+)?$/.test(value);// 是否为小数const isDot = value => /^\d+\.\d+$/.test(value)// 正浮点数保留两位数字const formatDot = (value)=> value.toString().match(/^\d+(?:\.\d{0,2})?/).[0]// 两个小数是否相等const epsEqu = (x,y)=> {return Math.abs(x - y) < Number.EPSILON;}
Number.EPSILON 属性表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值
二、文件与URL
1、通用文件下载
// axios通用文件下载const downLoadFile = (url, fileName, callback, fileType) => {const options = {method: 'GET',url: `${url}`,responseType: 'blob',};axios(options).then((res) => {if (callback) {let files = new window.File([res.data], fileName, {type:fileType});callback(files);} else {// 将blob对象转换为域名结合式的urllet blobUrl = window.URL.createObjectURL(res.data);let link = document.createElement('a');link.style.display = 'none';link.href = blobUrl;link.download = fileName;document.body.appendChild(link);link.click();link.parentNode ? link.parentNode.removeChild(link) : document.body.removeChild(link);window.URL.revokeObjectURL(blobUrl);}});}// fetch通用文件下载const fetchDownLoadFile = (url,fileName,token,submitData) => {const options = {method: "post",url: `${url}`,headers: {"Content-Type": "application/json;charset=utf-8",Authorization:token,},body: JSON.stringify({...submitData}),};fetch(url, options).then((response) => response.blob()).then((res) => {// 将blob对象转换为域名结合式的urllet blobUrl = window.URL.createObjectURL(res);let link = document.createElement("a");link.style.display = "none";link.href = blobUrl;link.download = fileName;document.body.appendChild(link);link.click();link.parentNode ? link.parentNode.removeChild(link) : document.body.removeChild(link);window.URL.revokeObjectURL(blobUrl);});};
2、文件流转dataUrl
const handleFlieReader = (file: any) => {return new Promise((resolve, reject) => {let reader = new FileReader();reader.onload = function (e: any) {let data: any = e.target.result;resolve(data);};reader.readAsDataURL(file);});};//图片文件url 转 base64function urlToBase64(url, type) {return new Promise ((resolve,reject) => {let image = new Image();image.onload = function() {let canvas = document.createElement('canvas');canvas.width = image?.naturalWidth;canvas.height = image?.naturalHeight;// 将图片插入画布并开始绘制canvas.getContext('2d').drawImage(image, 0, 0);let result = canvas.toDataURL(type || 'image/png')resolve(result);};// CORS 策略,会存在跨域问题https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerrorimage.setAttribute("crossOrigin",'Anonymous');image.src = url;// 图片加载失败的错误处理image.onerror = () => {reject(new Error('urlToBase64 error'));};}
3、dataUrl转文件流
//way 1:function dataURLtoBlob(dataurl: string) {let arr: any = dataurl.split(','),mime = arr[0].match(/:(.*?);/)[1],bstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new Blob([u8arr], { type: mime });}function blobToFile(theBlob: any, fileName: any) {theBlob.lastModifiedDate = new Date();theBlob.name = fileName;const file = new window.File([theBlob], fileName, {type: theBlob?.type || 'image/png',});return file;}//way 2:async function dataUrlToFile(dataUrl: string, fileName: string): Promise<File> {const res: Response = await fetch(dataUrl);const blob: Blob = await res.blob();return new File([blob], fileName, { type: 'image/png' });}
4、Canvas转Blob兼容性处理
const getCanvasToBlob = (canvas: any, type: any) => {if (!HTMLCanvasElement.prototype.toBlob) {Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {value: function (callback: any, type: any, quality: any) {let binStr = atob(this.toDataURL(type, quality).split(',')[1]),len = binStr.length,arr = new Uint8Array(len);for (let i = 0; i < len; i++) {arr[i] = binStr.charCodeAt(i);}callback(new Blob([arr], { type: type || 'image/png' }));},});}return new Promise((resolve, reject) => {return canvas.toBlob((blob: any) => resolve(blob), type);});};
5、是否为安全URL
const validateURL = (url) => {let urlReg = /(http|https):\/\/([\w.]+\/?)\S*/;if (!url || (url && !urlReg.test(url))) {return false;} else {try {const parsed = new URL(url);return ['https:', 'http:'].includes(parsed?.protocol);} catch (error) {return false;}}};
6、获取URL中的查询参数
let urlParams = new URLSearchParams('?post=1234&action=edit');console.log(urlParams.get('action')); // "edit"
三、表单校验
1、生成随机密码
const getRandomPassword = () => {let lowerCaseStrs = 'abcdefghijklmnopqrstuvwxyz',upperCaseStrs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',numberChar = '0123456789';const passArr = Array.from({ length: 3 }).fill(0);const password = passArr.reduce((acc) => {let lower = lowerCaseStrs.charAt(Math.floor(Math.random() * lowerCaseStrs.length));let upper = upperCaseStrs.charAt(Math.floor(Math.random() * upperCaseStrs.length));let num = numberChar.charAt(Math.floor(Math.random() * numberChar.length));return [...acc, `${lower}${upper}${num}`].join('');}, []);return password;};
2、校验手机号、邮箱、密码
// 校验手机号const validatePhone = (value: any) => {const phoneReg = /^1[3456789]\d{9}$/;if (phoneReg.test(value)){return true}else{if(value?.trim()){console.log("手机号格式不正确!")}return false}};// 校验邮箱const validateMail = (value: any) => {const mailReg = new RegExp('^[a-z0-9A-Z]+[- | a-z0-9A-Z . _]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-z]{2,}$');if (mailReg.test(value)){return true}else{if(value?.trim()){console.log("邮箱格式不正确!")}return false}};// 校验密码const validatePassword = (val:any)=>{//至少包含一位大小写字母,只能输入ASCII 码 !-~ 范围,6-20位const pwdReg = /^(?=.*?[A-Z])(?=.*?[a-z])[!-~]{6,20}$/;if(pwdReg.test(val)){return true}else{if(value?.trim()){console.log("密码格式不正确!")}return false}}
四、日期
1、格式化日期
function formatDate(date) {let d;if (date) {d = new Date(date);} else {d = new Date();}let month = '' + (d.getMonth() + 1);let day = `${d.getDate()}`;let year = d.getFullYear();if (month.length < 2) month = '0' + month;if (day.length < 2) day = '0' + day;return [year, month, day].join('/');}//formatDate()//'2022/01/06'
五、字符串与JSON
1、单位数补位
function numExpand(num) {const str = `${num}`;return str.length === 1 ? str.padStart(2, '0') : str;}
2、判断是否为JSON
const isJSON = (str: any) => {if (typeof str === 'string') {try {let obj = JSON.parse(str);if (typeof obj === 'object' && obj) {return true;} else {return false;}} catch (e) {return false;}}console.log('It is not a string!');return false;};
六、多媒体
1、浏览器是否支持音视频播放
//音频编解码格式浏览器是否支持const supportsAudioPlayback = (contentType) => {let audioElement = document.createElement('audio');if (audioElement.canPlayType) {return !!audioElement.canPlayType(contentType).replace(/no/, '');}};//视频编解码格式浏览器是否支持const supportsVideoPlayback = function (contentType) {let videoElement = document.createElement('video');if (videoElement.canPlayType) {let playable = videoElement.canPlayType(contentType);if (playable.toLowerCase() === 'maybe' || playable.toLowerCase() === 'probably') {return true;}}return false;};
七、交互
1、简易防抖、节流
// 防抖function debounce(fn, wait = 50, immediate) {// immediate 表示第一次是否立即执行let timer = null;return function(...args) {let context = this;if (timer) clearTimeout(timer);if (!timer && immediate) {fn.apply(context, args);}timer = setTimeout(() => {fn.apply(context, args);}, wait);};}// 节流function throttle(fn, wait) {let previous = 0;let timer = null;return function(...args) {let context = this;let now = +new Date();if (now - previous < wait) {if (timer) clearTimeout(timer);timer = setTimeout(() => {previous = now;fn.apply(context, args);}, wait);} else {previous = now;fn.apply(context, args);}};}
八、水印
1、Canvas生成网页水印
// canvas 实现 watermarkfunction getCanvasWaterMark({width = '200px',height = '150px',textAlign = 'center',textBaseline = 'middle',font = '20px Microsoft Yahei',fillStyle = '#EFF0F1',content = '请勿外传',rotate = '30',} = {}) {const canvas = document.createElement('canvas');canvas.setAttribute('width', width);canvas.setAttribute('height', height);const ctx = canvas.getContext('2d');if (ctx) {ctx.textAlign = textAlign as CanvasTextAlign;ctx.textBaseline = textBaseline as CanvasTextBaseline;ctx.font = font;ctx.fillStyle = fillStyle;ctx.rotate((Math.PI / 180) * Number(rotate ?? 0));ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2);}const base64Url = canvas.toDataURL();return base64Url;}// 页面展示 watermark 图片function showWaterMark({ base64Url = '', container = document.body, zIndex = 1000 } = {}) {const __wm = document.querySelector('.__wm');const watermarkDiv = __wm || document.createElement('div');const styleStr = `position:absolute;top:0;left:0;width:100%;height:100%;z-index:${zIndex};pointer-events:none;background-repeat:repeat;background-image:url('${base64Url}')`;watermarkDiv.setAttribute('style', styleStr);watermarkDiv.classList.add('__wm');if (!__wm) {container.style.position = 'relative';container.insertBefore(watermarkDiv, container.firstChild);}// 监听 watermark 容器样式更改const observerWaterMark = () => {const MutationObserver = window.MutationObserver;if (MutationObserver) {let mo: any = new MutationObserver(function () {const __wm = document.querySelector('.__wm');// 只在__wm元素变动才重新调用 __canvasWMif ((__wm && __wm.getAttribute('style') !== styleStr) || !__wm) {// 避免一直触发mo.disconnect();mo = null;showWaterMark({ base64Url: getCanvasWaterMark({}) });}});mo.observe(container, {attributes: true,subtree: true,childList: true,});}};observerWaterMark();}
2、Canvas 生成图片水印
// 绘制图片水印const drawImgWaterMark = (url = '', text = '请勿外传', callback?: any) => {if (url) {const img = new Image();img.src = url;img.crossOrigin = 'anonymous';img.onload = function () {let canvas = document.createElement('canvas');canvas.width = img.width;canvas.height = img.height;let canvasWidth = canvas.width;let canvasHeight = canvas.height;const ctx = canvas.getContext('2d');if (ctx) {// 文字样式ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.font = `${canvasWidth / 48}px Microsoft Yahei`;ctx.fillStyle = 'rgba(255, 255, 255, 0.6)';let widthGap = canvasWidth / 12;let heightGap = canvasHeight / 16;let textWidth = ctx.measureText(text)?.width;let textHeight = textWidth * Math.sin((20 * Math.PI) / 180);let fwidth = textWidth + widthGap,fheight = textHeight + heightGap;for (let hh = -canvasHeight; hh <= canvasHeight + fheight; hh += fheight) {for (let ww = -canvasWidth; ww <= canvasWidth + fwidth; ww += fwidth) {ctx.setTransform(1, 0, 0, 1, 0, 0);ctx.translate(ww, hh);// 文字旋转ctx.rotate((-20 * Math.PI) / 180);ctx.fillText(text, -fwidth / 2, fheight / 2);}}}const base64Url = canvas.toDataURL();callback && callback(base64Url);};}};
九、大文件上传
1、获取文件MD5
const getFileMd5 = (file: any) => {return new Promise((resolve, reject) => {const chunkSize = 2 * 1024 * 1024,chunks = Math.ceil(file.size / chunkSize),currentChunk = 0,spark = new SparkMD5.ArrayBuffer(),fileReader = new FileReader();const tempFile: any[] = [];if (chunks > 2) {// 大文件分别取前中后三段样本来生成md5const mid = chunks >> 1;tempFile.push(file.slice(0, currentChunk * chunkSize));tempFile.push(file.slice(mid * chunkSize, (mid + 1) * chunkSize));tempFile.push(file.slice((chunks - 1) * chunkSize, chunks * chunkSize));} else {tempFile.push(file);}fileReader.readAsArrayBuffer(new Blob(tempFile));fileReader.onload = async (e) => {spark.append(e.target?.result as ArrayBuffer);const md5 = spark.end();resolve({md5,name: file.name,resourceType: resourceType,size: file.size,});};fileReader.onerror = function () {message.error('读取文件出错!');reject('读取文件出错!');handleRemove();};});};
2、上传前请求 OSS对象 的权限id、签名、host地址;资源对象的 id等信息
3、上传成功后,根据资源对象 id 获取 文件地址
十、图片预览
const onPreview = async (src: string) => {const image = new Image();image.src = src;const imgWindow = window.open(src);imgWindow?.document.write(image.outerHTML);};
