一、数字

1、数字格式化

  • 数字千分位逗号分隔:new Intl.NumberFormat().format(num)

    1. const formatNumber = (num)=> new Intl.NumberFormat().format(num);
    2. console.log([formatNumber("12345"),formatNumber(12345)])
    3. //["12,345", "12,345"]
  • 货币化:new Intl.NumberFormat(‘zh-CN’,{ style: ‘currency’, currency: ‘CNY’,maximumFractionDigits: maxDig }).format(num)

    • 常见方法

      1. // 格式化货币
      2. const formatMoney = (value, type = 2) => {
      3. let s = value < 0 ? Math.abs(value) : value;
      4. if (/[^0-9.]/.test(s)) return '¥ 0.00';
      5. if (s === null || s === 'null' || s === '') return '¥ 0.00';
      6. s = s.toString().replace(/^(\d*)$/, '$1.');
      7. s = (s + '00').replace(/(\d*\.\d\d)\d*/, '$1');
      8. s = s.replace('.', ',');
      9. var re = /(\d)(\d{3},)/;
      10. while (re.test(s)) s = s.replace(re, '$1,$2');
      11. s = s.replace(/,(\d\d)$/, '.$1');
      12. if (type === 0) {
      13. var a = s.split('.');
      14. if (a[1] === '00') {
      15. s = a[0];
      16. }
      17. }
      18. return value < 0 ? '¥ -' + s : '¥ ' + s;
      19. };
      20. console.log(formatMoney(12345.6789))
      21. //¥ 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 {

      1. const formatVal = new Intl.NumberFormat(locale, {
      2. style: 'currency',
      3. currency,
      4. ...(maxDig ? { maximumFractionDigits: maxDig } : {}),
      5. }).format(parseFloat(String(num)));
      6. return formatVal || '¥ 0';

      } catch (err) {

      1. return '¥ 0';

      } } };

  1. - 大数据量统计
  2. ```javascript
  3. const nums = [1234, 123456.789, 123456789123, 123456789123456,123456789123456789]
  4. nums.map(num => {
  5. return new Intl.NumberFormat('zh-CN', { notation: "compact" }).format(num)
  6. })
  7. //["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%”]
  1. <a name="lWZxg"></a>
  2. ### 2、数字校验
  3. ```javascript
  4. // 是否是数字
  5. // 1、js方法
  6. const isNumber = value => !isNaN(parseFloat(value)) && isFinite(value);
  7. // 2、正则
  8. const isNumberRegex = value=> /^\d{1,}$/.test(value)
  9. // 是否是正数
  10. // 1、js方法
  11. const isPositive = value => isNumber(value) && Math.sign(value) === 1;
  12. // 2、正则判断正浮点数
  13. const isPositiveFloat = value => Math.sign(Number(value ?? 0) || 0) === 1 && /^(?:[1-9]\d*|0)?(?:\.\d+)?$/.test(value);
  14. // 是否为小数
  15. const isDot = value => /^\d+\.\d+$/.test(value)
  16. // 正浮点数保留两位数字
  17. const formatDot = (value)=> value.toString().match(/^\d+(?:\.\d{0,2})?/).[0]
  18. // 两个小数是否相等
  19. const epsEqu = (x,y)=> {
  20. return Math.abs(x - y) < Number.EPSILON;
  21. }

Number.EPSILON 属性表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值

二、文件与URL

1、通用文件下载

  1. // axios通用文件下载
  2. const downLoadFile = (url, fileName, callback, fileType) => {
  3. const options = {
  4. method: 'GET',
  5. url: `${url}`,
  6. responseType: 'blob',
  7. };
  8. axios(options).then((res) => {
  9. if (callback) {
  10. let files = new window.File([res.data], fileName, {
  11. type:fileType
  12. });
  13. callback(files);
  14. } else {
  15. // 将blob对象转换为域名结合式的url
  16. let blobUrl = window.URL.createObjectURL(res.data);
  17. let link = document.createElement('a');
  18. link.style.display = 'none';
  19. link.href = blobUrl;
  20. link.download = fileName;
  21. document.body.appendChild(link);
  22. link.click();
  23. link.parentNode ? link.parentNode.removeChild(link) : document.body.removeChild(link);
  24. window.URL.revokeObjectURL(blobUrl);
  25. }
  26. });
  27. }
  28. // fetch通用文件下载
  29. const fetchDownLoadFile = (url,fileName,token,submitData) => {
  30. const options = {
  31. method: "post",
  32. url: `${url}`,
  33. headers: {
  34. "Content-Type": "application/json;charset=utf-8",
  35. Authorization:token,
  36. },
  37. body: JSON.stringify({...submitData}),
  38. };
  39. fetch(url, options)
  40. .then((response) => response.blob())
  41. .then((res) => {
  42. // 将blob对象转换为域名结合式的url
  43. let blobUrl = window.URL.createObjectURL(res);
  44. let link = document.createElement("a");
  45. link.style.display = "none";
  46. link.href = blobUrl;
  47. link.download = fileName;
  48. document.body.appendChild(link);
  49. link.click();
  50. link.parentNode ? link.parentNode.removeChild(link) : document.body.removeChild(link);
  51. window.URL.revokeObjectURL(blobUrl);
  52. });
  53. };

2、文件流转dataUrl

  1. const handleFlieReader = (file: any) => {
  2. return new Promise((resolve, reject) => {
  3. let reader = new FileReader();
  4. reader.onload = function (e: any) {
  5. let data: any = e.target.result;
  6. resolve(data);
  7. };
  8. reader.readAsDataURL(file);
  9. });
  10. };
  11. //图片文件url 转 base64
  12. function urlToBase64(url, type) {
  13. return new Promise ((resolve,reject) => {
  14. let image = new Image();
  15. image.onload = function() {
  16. let canvas = document.createElement('canvas');
  17. canvas.width = image?.naturalWidth;
  18. canvas.height = image?.naturalHeight;
  19. // 将图片插入画布并开始绘制
  20. canvas.getContext('2d').drawImage(image, 0, 0);
  21. let result = canvas.toDataURL(type || 'image/png')
  22. resolve(result);
  23. };
  24. // CORS 策略,会存在跨域问题https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror
  25. image.setAttribute("crossOrigin",'Anonymous');
  26. image.src = url;
  27. // 图片加载失败的错误处理
  28. image.onerror = () => {
  29. reject(new Error('urlToBase64 error'));
  30. };
  31. }

3、dataUrl转文件流

  1. //way 1:
  2. function dataURLtoBlob(dataurl: string) {
  3. let arr: any = dataurl.split(','),
  4. mime = arr[0].match(/:(.*?);/)[1],
  5. bstr = atob(arr[1]),
  6. n = bstr.length,
  7. u8arr = new Uint8Array(n);
  8. while (n--) {
  9. u8arr[n] = bstr.charCodeAt(n);
  10. }
  11. return new Blob([u8arr], { type: mime });
  12. }
  13. function blobToFile(theBlob: any, fileName: any) {
  14. theBlob.lastModifiedDate = new Date();
  15. theBlob.name = fileName;
  16. const file = new window.File([theBlob], fileName, {
  17. type: theBlob?.type || 'image/png',
  18. });
  19. return file;
  20. }
  21. //way 2:
  22. async function dataUrlToFile(dataUrl: string, fileName: string): Promise<File> {
  23. const res: Response = await fetch(dataUrl);
  24. const blob: Blob = await res.blob();
  25. return new File([blob], fileName, { type: 'image/png' });
  26. }

4、Canvas转Blob兼容性处理

  1. const getCanvasToBlob = (canvas: any, type: any) => {
  2. if (!HTMLCanvasElement.prototype.toBlob) {
  3. Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
  4. value: function (callback: any, type: any, quality: any) {
  5. let binStr = atob(this.toDataURL(type, quality).split(',')[1]),
  6. len = binStr.length,
  7. arr = new Uint8Array(len);
  8. for (let i = 0; i < len; i++) {
  9. arr[i] = binStr.charCodeAt(i);
  10. }
  11. callback(new Blob([arr], { type: type || 'image/png' }));
  12. },
  13. });
  14. }
  15. return new Promise((resolve, reject) => {
  16. return canvas.toBlob((blob: any) => resolve(blob), type);
  17. });
  18. };

5、是否为安全URL

  1. const validateURL = (url) => {
  2. let urlReg = /(http|https):\/\/([\w.]+\/?)\S*/;
  3. if (!url || (url && !urlReg.test(url))) {
  4. return false;
  5. } else {
  6. try {
  7. const parsed = new URL(url);
  8. return ['https:', 'http:'].includes(parsed?.protocol);
  9. } catch (error) {
  10. return false;
  11. }
  12. }
  13. };

6、获取URL中的查询参数

  1. let urlParams = new URLSearchParams('?post=1234&action=edit');
  2. console.log(urlParams.get('action')); // "edit"

三、表单校验

1、生成随机密码

  1. const getRandomPassword = () => {
  2. let lowerCaseStrs = 'abcdefghijklmnopqrstuvwxyz',
  3. upperCaseStrs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
  4. numberChar = '0123456789';
  5. const passArr = Array.from({ length: 3 }).fill(0);
  6. const password = passArr.reduce((acc) => {
  7. let lower = lowerCaseStrs.charAt(Math.floor(Math.random() * lowerCaseStrs.length));
  8. let upper = upperCaseStrs.charAt(Math.floor(Math.random() * upperCaseStrs.length));
  9. let num = numberChar.charAt(Math.floor(Math.random() * numberChar.length));
  10. return [...acc, `${lower}${upper}${num}`].join('');
  11. }, []);
  12. return password;
  13. };

2、校验手机号、邮箱、密码

  1. // 校验手机号
  2. const validatePhone = (value: any) => {
  3. const phoneReg = /^1[3456789]\d{9}$/;
  4. if (phoneReg.test(value)){
  5. return true
  6. }else{
  7. if(value?.trim()){
  8. console.log("手机号格式不正确!")
  9. }
  10. return false
  11. }
  12. };
  13. // 校验邮箱
  14. const validateMail = (value: any) => {
  15. const mailReg = new RegExp(
  16. '^[a-z0-9A-Z]+[- | a-z0-9A-Z . _]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-z]{2,}$'
  17. );
  18. if (mailReg.test(value)){
  19. return true
  20. }else{
  21. if(value?.trim()){
  22. console.log("邮箱格式不正确!")
  23. }
  24. return false
  25. }
  26. };
  27. // 校验密码
  28. const validatePassword = (val:any)=>{
  29. //至少包含一位大小写字母,只能输入ASCII 码 !-~ 范围,6-20位
  30. const pwdReg = /^(?=.*?[A-Z])(?=.*?[a-z])[!-~]{6,20}$/;
  31. if(pwdReg.test(val)){
  32. return true
  33. }else{
  34. if(value?.trim()){
  35. console.log("密码格式不正确!")
  36. }
  37. return false
  38. }
  39. }

四、日期

1、格式化日期

  1. function formatDate(date) {
  2. let d;
  3. if (date) {
  4. d = new Date(date);
  5. } else {
  6. d = new Date();
  7. }
  8. let month = '' + (d.getMonth() + 1);
  9. let day = `${d.getDate()}`;
  10. let year = d.getFullYear();
  11. if (month.length < 2) month = '0' + month;
  12. if (day.length < 2) day = '0' + day;
  13. return [year, month, day].join('/');
  14. }
  15. //formatDate()
  16. //'2022/01/06'

五、字符串与JSON

1、单位数补位

  1. function numExpand(num) {
  2. const str = `${num}`;
  3. return str.length === 1 ? str.padStart(2, '0') : str;
  4. }

2、判断是否为JSON

  1. const isJSON = (str: any) => {
  2. if (typeof str === 'string') {
  3. try {
  4. let obj = JSON.parse(str);
  5. if (typeof obj === 'object' && obj) {
  6. return true;
  7. } else {
  8. return false;
  9. }
  10. } catch (e) {
  11. return false;
  12. }
  13. }
  14. console.log('It is not a string!');
  15. return false;
  16. };

六、多媒体

1、浏览器是否支持音视频播放

  1. //音频编解码格式浏览器是否支持
  2. const supportsAudioPlayback = (contentType) => {
  3. let audioElement = document.createElement('audio');
  4. if (audioElement.canPlayType) {
  5. return !!audioElement.canPlayType(contentType).replace(/no/, '');
  6. }
  7. };
  8. //视频编解码格式浏览器是否支持
  9. const supportsVideoPlayback = function (contentType) {
  10. let videoElement = document.createElement('video');
  11. if (videoElement.canPlayType) {
  12. let playable = videoElement.canPlayType(contentType);
  13. if (playable.toLowerCase() === 'maybe' || playable.toLowerCase() === 'probably') {
  14. return true;
  15. }
  16. }
  17. return false;
  18. };

七、交互

1、简易防抖、节流

  1. // 防抖
  2. function debounce(fn, wait = 50, immediate) {// immediate 表示第一次是否立即执行
  3. let timer = null;
  4. return function(...args) {
  5. let context = this;
  6. if (timer) clearTimeout(timer);
  7. if (!timer && immediate) {
  8. fn.apply(context, args);
  9. }
  10. timer = setTimeout(() => {
  11. fn.apply(context, args);
  12. }, wait);
  13. };
  14. }
  15. // 节流
  16. function throttle(fn, wait) {
  17. let previous = 0;
  18. let timer = null;
  19. return function(...args) {
  20. let context = this;
  21. let now = +new Date();
  22. if (now - previous < wait) {
  23. if (timer) clearTimeout(timer);
  24. timer = setTimeout(() => {
  25. previous = now;
  26. fn.apply(context, args);
  27. }, wait);
  28. } else {
  29. previous = now;
  30. fn.apply(context, args);
  31. }
  32. };
  33. }

八、水印

1、Canvas生成网页水印

  1. // canvas 实现 watermark
  2. function getCanvasWaterMark({
  3. width = '200px',
  4. height = '150px',
  5. textAlign = 'center',
  6. textBaseline = 'middle',
  7. font = '20px Microsoft Yahei',
  8. fillStyle = '#EFF0F1',
  9. content = '请勿外传',
  10. rotate = '30',
  11. } = {}) {
  12. const canvas = document.createElement('canvas');
  13. canvas.setAttribute('width', width);
  14. canvas.setAttribute('height', height);
  15. const ctx = canvas.getContext('2d');
  16. if (ctx) {
  17. ctx.textAlign = textAlign as CanvasTextAlign;
  18. ctx.textBaseline = textBaseline as CanvasTextBaseline;
  19. ctx.font = font;
  20. ctx.fillStyle = fillStyle;
  21. ctx.rotate((Math.PI / 180) * Number(rotate ?? 0));
  22. ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2);
  23. }
  24. const base64Url = canvas.toDataURL();
  25. return base64Url;
  26. }
  27. // 页面展示 watermark 图片
  28. function showWaterMark({ base64Url = '', container = document.body, zIndex = 1000 } = {}) {
  29. const __wm = document.querySelector('.__wm');
  30. const watermarkDiv = __wm || document.createElement('div');
  31. const styleStr = `
  32. position:absolute;
  33. top:0;
  34. left:0;
  35. width:100%;
  36. height:100%;
  37. z-index:${zIndex};
  38. pointer-events:none;
  39. background-repeat:repeat;
  40. background-image:url('${base64Url}')`;
  41. watermarkDiv.setAttribute('style', styleStr);
  42. watermarkDiv.classList.add('__wm');
  43. if (!__wm) {
  44. container.style.position = 'relative';
  45. container.insertBefore(watermarkDiv, container.firstChild);
  46. }
  47. // 监听 watermark 容器样式更改
  48. const observerWaterMark = () => {
  49. const MutationObserver = window.MutationObserver;
  50. if (MutationObserver) {
  51. let mo: any = new MutationObserver(function () {
  52. const __wm = document.querySelector('.__wm');
  53. // 只在__wm元素变动才重新调用 __canvasWM
  54. if ((__wm && __wm.getAttribute('style') !== styleStr) || !__wm) {
  55. // 避免一直触发
  56. mo.disconnect();
  57. mo = null;
  58. showWaterMark({ base64Url: getCanvasWaterMark({}) });
  59. }
  60. });
  61. mo.observe(container, {
  62. attributes: true,
  63. subtree: true,
  64. childList: true,
  65. });
  66. }
  67. };
  68. observerWaterMark();
  69. }

2、Canvas 生成图片水印

  1. // 绘制图片水印
  2. const drawImgWaterMark = (url = '', text = '请勿外传', callback?: any) => {
  3. if (url) {
  4. const img = new Image();
  5. img.src = url;
  6. img.crossOrigin = 'anonymous';
  7. img.onload = function () {
  8. let canvas = document.createElement('canvas');
  9. canvas.width = img.width;
  10. canvas.height = img.height;
  11. let canvasWidth = canvas.width;
  12. let canvasHeight = canvas.height;
  13. const ctx = canvas.getContext('2d');
  14. if (ctx) {
  15. // 文字样式
  16. ctx.textAlign = 'center';
  17. ctx.textBaseline = 'middle';
  18. ctx.font = `${canvasWidth / 48}px Microsoft Yahei`;
  19. ctx.fillStyle = 'rgba(255, 255, 255, 0.6)';
  20. let widthGap = canvasWidth / 12;
  21. let heightGap = canvasHeight / 16;
  22. let textWidth = ctx.measureText(text)?.width;
  23. let textHeight = textWidth * Math.sin((20 * Math.PI) / 180);
  24. let fwidth = textWidth + widthGap,
  25. fheight = textHeight + heightGap;
  26. for (let hh = -canvasHeight; hh <= canvasHeight + fheight; hh += fheight) {
  27. for (let ww = -canvasWidth; ww <= canvasWidth + fwidth; ww += fwidth) {
  28. ctx.setTransform(1, 0, 0, 1, 0, 0);
  29. ctx.translate(ww, hh);
  30. // 文字旋转
  31. ctx.rotate((-20 * Math.PI) / 180);
  32. ctx.fillText(text, -fwidth / 2, fheight / 2);
  33. }
  34. }
  35. }
  36. const base64Url = canvas.toDataURL();
  37. callback && callback(base64Url);
  38. };
  39. }
  40. };

九、大文件上传

1、获取文件MD5

  1. const getFileMd5 = (file: any) => {
  2. return new Promise((resolve, reject) => {
  3. const chunkSize = 2 * 1024 * 1024,
  4. chunks = Math.ceil(file.size / chunkSize),
  5. currentChunk = 0,
  6. spark = new SparkMD5.ArrayBuffer(),
  7. fileReader = new FileReader();
  8. const tempFile: any[] = [];
  9. if (chunks > 2) {
  10. // 大文件分别取前中后三段样本来生成md5
  11. const mid = chunks >> 1;
  12. tempFile.push(file.slice(0, currentChunk * chunkSize));
  13. tempFile.push(file.slice(mid * chunkSize, (mid + 1) * chunkSize));
  14. tempFile.push(file.slice((chunks - 1) * chunkSize, chunks * chunkSize));
  15. } else {
  16. tempFile.push(file);
  17. }
  18. fileReader.readAsArrayBuffer(new Blob(tempFile));
  19. fileReader.onload = async (e) => {
  20. spark.append(e.target?.result as ArrayBuffer);
  21. const md5 = spark.end();
  22. resolve({
  23. md5,
  24. name: file.name,
  25. resourceType: resourceType,
  26. size: file.size,
  27. });
  28. };
  29. fileReader.onerror = function () {
  30. message.error('读取文件出错!');
  31. reject('读取文件出错!');
  32. handleRemove();
  33. };
  34. });
  35. };

2、上传前请求 OSS对象 的权限id、签名、host地址;资源对象的 id等信息

3、上传成功后,根据资源对象 id 获取 文件地址

十、图片预览

  1. const onPreview = async (src: string) => {
  2. const image = new Image();
  3. image.src = src;
  4. const imgWindow = window.open(src);
  5. imgWindow?.document.write(image.outerHTML);
  6. };