# 个人常用前端工具类 **Repository Path**: fxym888/utils ## Basic Information - **Project Name**: 个人常用前端工具类 - **Description**: 个人常用前端工具类 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-01-19 - **Last Updated**: 2023-01-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 持续更新觉得比较实用的一些工具类,非工具库,手动封装版【部分方法来源于网络,侵权请私信】 # 防抖 ```js // debounce.js let timeout = null function debounce(fn, wait) { if (timeout !== null) clearTimeout(timeout) timeout = setTimeout(fn, wait) } export default debounce // 使用方法 debounce(() => { //业务代码 },1000) ``` # 节流 ```js // throttle.js let timer, args, that; function throttle(func, wait) { that = this; args = arguments; // 把timer作为节流阀 来控制传递的函数是否执行 if (!timer) { timer = setTimeout(function () { // 定时器到达预定时间后改变节流阀的状态 来执行下一次传入的回调函数 func.apply(that, args); timer = null; }, wait); } } export default throttle // 使用方法 throttle(() => { //业务代码 },1000) ``` # base64文件转File文件流 ```js // 方法一,【万能的fetch可以转换一些流,但是首先nginx配置得支持,遇过坑,怕了怕了】 const baseToFile = (base64) => { fetch(base64, { method: 'get', responseType: 'blob', }).then(res => { return res.blob(); }).then(res => { let fileOfBlobMin = new File([res], new Date().getTime() + ".jpg"); // 命名图片名 return fileOfBlobMin }) } export { baseToFile } //-------------------------------- // 方法二 //1,先将base64转换为blob const dataURLtoBlob = (dataurl) => { var arr = 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 }); } //2,再将blob转换为file const blobToFile = (theBlob, fileName) => { theBlob.lastModifiedDate = new Date(); // 文件最后的修改日期 theBlob.name = fileName; // 文件名 return new File([theBlob], fileName, { type: theBlob.type, lastModified: Date.now() }); } // 使用方法 // let BlobImg = dataURLtoBlob(queryParams.imgSrc) // let fileImg = blobToFile(BlobBig,nameBig) ``` # base图片压缩方案【可以设置分辨率,暂定100k以下,需要的话自己加个参数改就行】 ```js // base64图片压缩算法 var dealImage = (base64, w, callback) => { var newImage = new Image(); var quality = 1; //压缩系数0-1之间 newImage.src = base64; newImage.setAttribute("crossOrigin", 'Anonymous'); //url为外域时需要 var imgWidth, imgHeight; newImage.onload = function () { imgWidth = this.width; imgHeight = this.height; var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); console.log('Math.max(imgWidth, imgHeight)',Math.max(imgWidth, imgHeight)) if (Math.max(imgWidth, imgHeight) > w) { if (imgWidth > imgHeight) { canvas.width = w; canvas.height = w * imgHeight / imgWidth; } else { canvas.height = w; canvas.width = w * imgWidth / imgHeight; } } else { canvas.width = imgWidth; canvas.height = imgHeight; quality = 1; } ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); var base640 = canvas.toDataURL("image/jpeg", quality); //压缩语句 // 如想确保图片压缩到自己想要的尺寸,如要求在100kb以下,请加以下语句,quality初始值根据情况自定 console.log(base640.length / 1024) while (base640.length / 1024 > 100) { quality -= 0.01; base640 = canvas.toDataURL("image/jpeg", quality); } callback(base640);//必须通过回调函数返回,否则无法及时拿到该值 } } export default dealImage ``` # File文件流压缩 ```js const compressImage = (file,quality,callbak) => { let options = { file: file, quality: quality, mimeType: 'auto', maxWidth: 2000, maxHeight: 2000, width: 0, height: 0, minWidth: 0, minHeight: 0, convertSize: 1024,//单位:Byte 多大的png转为jpg,然后压缩 loose: true,// 在非宽松模式下,用户期待的输出宽高没有大于源图片的宽高情况下,输出文件大小大于源文件,返回源文件 redressOrientation: true,//转化后的方向信息 // 压缩前回调 beforeCompress: function (result) { console.log('压缩之前图片尺寸大小: ', result.size/1024 ,'kb') console.log('mime 类型: ', result.type) }, // 压缩成功回调 success: function (result) { console.log('压缩之后图片尺寸大小: ', result.size/1024 ,'kb') console.log('mime 类型: ', result.type) console.log( '实际压缩率: ', (((file.size - result.size) / file.size) * 100).toFixed(2) + '%' ) callbak(result); }, // 发生错误 error: function (msg) { console.error(msg) }, } return new ImageCompressor(options) } ``` # 调用摄像头方法[需要https协议,ios微信不兼容webRTC需要nginx环境配置webRTC,非常坑] ```js //调用摄像头权限 const getCompetence = () => { showVideo.value = true nextTick(() => { VideoOsFlag.value = false; thisCancas = document.getElementById("canvasCamera"); thisContext = thisCancas.getContext("2d"); thisVideo = document.getElementById("videoCamera"); closedPhono.value = thisVideo; const MediaConstraint = { audio: false, video: {width: 250, height: 250, transform: "rotateY(180deg)"}, }; if (navigator.mediaDevices.getUserMedia) { // 最新标准API navigator.mediaDevices.getUserMedia(MediaConstraint) .then(function (stream) { if ("srcObject" in thisVideo) { thisVideo.srcObject = stream; } else { thisVideo.src = window.URL.createObjectURL(stream); } thisVideo.load(); thisVideo.play(); }) } else if (navigator.webkitGetUserMedia || navigator.mozGetUserMedia) { // webkit内核浏览器 if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {}; } // 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia // 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。 if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = function (constraints) { // 首先,如果有getUserMedia的话,就获得它 var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口 if (!getUserMedia) { return Promise.reject(new Error('getUserMedia is not implemented in this browser')); } // 否则,为老的navigator.getUserMedia方法包裹一个Promise return new Promise(function (resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject); }); } } navigator.mediaDevices.getUserMedia(MediaConstraint) .then(function (stream) { if ("srcObject" in thisVideo) { thisVideo.srcObject = stream; } else { thisVideo.src = window.URL.createObjectURL(stream); } thisVideo.load(); thisVideo.play(); }) } else if (navigator.getUserMedia) { // 旧版API navigator.getUserMedia(MediaConstraint) .then(function (stream) { if ("srcObject" in thisVideo) { thisVideo.srcObject = stream; } else { thisVideo.src = window.URL.createObjectURL(stream); } thisVideo.load(); thisVideo.play(); }) } }); }; ``` # 身份证正则校验,身份证都是算出来的,不是简单的判断位数就行。。具体看你愿不愿意注意细节了【sonar会报什么js复杂度过高的异味】 ```js // 身份证格式校验,很麻烦,网上copy的,测试功能正常,尽量别乱改 const validateIdNumber = (rule, value, callback) => { if (flag.value) { callback(); } let birthday = null; let sex = null; let age = -1; if (value.length != 15 && value.length != 18) callback(new Error("请输入正确身份证号码")); // 15位的全部或18位的前17位必须位数字 let str = value.length === 15 ? value : value.substring(0, 17); let regNum = /^\d+$/; if (!regNum.test(str)) callback(new Error("请输入正确身份证号码")); // 18位的最后一位可以是X或x let regLast = /[0-9Xx]/; let numLast = value.substring(17, 18); if (value.length === 18 && !regLast.test(numLast)) callback(new Error("请输入正确身份证号码")); // 前两位对应的区位码 let zoneArr = [11, 12, 13, 14, 15, 21, 22, 23, 31, 32, 33, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 61, 62, 63, 64, 65, 71, 81, 82, 91]; if (zoneArr.indexOf(parseInt(value.substring(0, 2))) == -1) callback(new Error("请输入正确身份证号码")); // 校验年份、月份、日子 let year = value.length === 15 ? `19${value.substring(6, 8)}` : value.substring(6, 10); let month = value.length === 15 ? value.substring(8, 10) : value.substring(10, 12); let day = value.length === 15 ? value.substring(10, 12) : value.substring(12, 14); let dayNum = parseInt(day); let monthNum = parseInt(month); let yearNum = parseInt(year); let currentYear = new Date().getFullYear(); if (yearNum < 1900 || yearNum > currentYear) callback(new Error("请输入正确身份证号码")); if (monthNum > 12 || monthNum < 1) callback(new Error("请输入正确身份证号码")); if ((monthNum === 1 || monthNum === 3 || monthNum === 5 || monthNum === 7 || monthNum === 8 || monthNum === 10 || monthNum === 12) && dayNum > 31) callback(new Error("请输入正确身份证号码")); if ((monthNum === 4 || monthNum === 6 || monthNum === 9 || monthNum === 11) && dayNum > 30) callback(new Error("请输入正确身份证号码")); // 校验闰平年二月的天数 if (monthNum === 2) { let leapYear = null; // 闰年 if (yearNum % 4 === 0 && yearNum % 100 != 0) leapYear = dayNum > 29 ? false : true; else {// 平年 leapYear = dayNum > 28 ? false : true; } if (!leapYear) { callback(new Error("请输入正确身份证号码")); } } // 校验 校验码 const powerList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; const paritybitList = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; let num = 0; let certArr = value.split('').map(Number).slice(0, 17); for (let i = 0; i < certArr.length; i++) { num += (certArr[i] * powerList[i]); } if (value[17] != paritybitList[num % 11]) { if (num % 11 === 2) { if (value[17] != 'x' && value[17] != 'X') { callback(new Error("请输入正确身份证号码")); } else { callback(); } } else { callback(new Error("请输入正确身份证号码")); } } callback(); } ``` # 滚动条样式优化 ```css /****谷歌浏览器下滚动条样式****/ ::-webkit-scrollbar { /* 滚动条整体部分 */ width: 5px; margin-right: 2px } ::-webkit-scrollbar-button { /* 滚动条两端的按钮 */ display: none; } ::-webkit-scrollbar:horizontal { height: 10px; margin-bottom: 2px } ::-webkit-scrollbar-track { /* 外层轨道 */ border-radius: 5px; } ::-webkit-scrollbar-track-piece { /*内层轨道,滚动条中间部分 */ background-color: #F5F5F5; border-radius: 5px; } ::-webkit-scrollbar-thumb { /* 滑块 */ width: 5px; border-radius: 5px; background: #E6E9EB; } ::-webkit-scrollbar-corner { /* 边角 */ width: 5px; } ::-webkit-scrollbar-thumb:hover { /* 鼠标移入滑块 */ background-color: #ccc; } /***********/ ```