UNPKG

wft-utils

Version:

The commonly used tool functions in daily development

1,311 lines (1,223 loc) 34.1 kB
/** * 深拷贝 * @param {object} source * @returns */ export function deepClone(source) { if (typeof source !== 'object' || source === null) return source const target = source.constructor === Array ? [] : {} for (let key in source) { if (source.hasOwnProperty(key)) { if (source[key] && typeof source[key] === 'object') { target[key] = deepClone(source[key]) } else { target[key] = source[key] } } } return target } /** * 异步深拷贝(不支持函数、Symbol、WeakMap、WeakSet等) * @param {*} obj * @param {*} cb * @returns */ export function deepCloneAsync(obj, cb) { return new Promise((resolve, reject) => { try { const { port1, port2 } = new MessageChannel() port1.postMessage(obj) port2.onmessage = data => { if (cb && typeof cb === 'function') cb(data.data) resolve(data.data) } } catch (e) { reject(e) } }) } /** * 同步监听事件 * @param {HTMLElement} el * @param {click | dblclick | contextmenu | mousedown | mousemove | mouseup | mousewheel | mouseenter | mouseover | mouseleave | mouseout} name * @param {Function} cb * @param {number} iteration * @returns */ export function syncEvent(el, name, cb, iteration = 0) { if (iteration < 0) { return console.error('SyncEvent: Iteration must be greater than or equal to 0') } function getElement(el) { return new Proxy(el, { get(target, key) { if (!key.startsWith('wait')) { return target[key] } return new Promise(resolve => { el.addEventListener(key.replace('wait', '').toLowerCase(), resolve, { once: true }) }) } }) } (async () => { const target = getElement(el) if (iteration === 0) { while (true) { const event = await target[`wait${name}`] cb(event) } } else { for (let i = 0; i < iteration; i++) { const event = await target[`wait${name}`] cb(event) } } })() } /** * 表单序列化 * @param {object} data * @returns */ export function serialize(data) { const list = [] Object.keys(data).forEach(key => { list.push(`${key}=${data[key]}`) }) return list.join('&') } /** * 随机打乱数组顺序 * @param {Array} arr * @returns */ export function shuffle(arr) { for (let i = arr.length - 1; i > 0; i--) { const randomIndex = Math.floor(Math.random() * (i + 1)); [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]] } return arr } /** * 随机获取一个Boolean值 * @returns */ export function getRandomBoolean() { return 0.5 - Math.random() >= 0 } /** * 随机获取一个颜色 * @returns */ export function getRandomColor() { return `#${Math.floor(Math.random() * 0xffffff).toString(16)}`; } /** * hex 转 rgba 格式 * @param {string} hex * @param {number} opacity * @returns */ export function hexToRgba(hex, opacity = 1) { return { r: parseInt("0x" + hex.slice(1, 3)), g: parseInt("0x" + hex.slice(3, 5)), b: parseInt("0x" + hex.slice(5, 7)), a: opacity } } /** * hex 转 rgb * @param {string} str * @returns */ export function hexToRgb(str) { str = str.replace('#', '') let hexs = str.match(/../g) for (let i = 0; i < 3; i++) { hexs[i] = parseInt(hexs[i], 16) } return hexs } /** * rgb 转 Hex * @param {number|string} r * @param {number|string} g * @param {number|string} b * @returns */ export function rgbToHex(r, g, b) { let hexs = [r.toString(16), g.toString(16), b.toString(16)] for (let i = 0; i < 3; i++) { if (hexs[i].length == 1) { hexs[i] = `0${hexs[i]}` } } return `#${hexs.join('')}` } /** * 匹配body之间的内容 富文本编辑器Editor中使用到了 * @param {Object} content */ export function getBody(content) { const REG_BODY = /<body[^>]*>([\s\S]*)<\/body>/; const result = REG_BODY.exec(content); if (result && result.length === 2) return result[1]; return content; } /** * 判断是否为空 校验 * @param {Object} val */ export function isEmpty(val) { if (Array.isArray(val) || val instanceof Array) { return val.length === 0 } else if (val instanceof Object || val.constructor === Object) { if (JSON.stringify(val) === '{}') return true } else { if (val === null || val === undefined || val === '') return true return false } return false } /** * 预览pdf * @param {File} blob * @param {string} docTitle */ export function preViewPdf(blob, docTitle) { const URL = window.URL || window.webkitURL; const href = URL.createObjectURL(new Blob([blob], { type: 'application/pdf; charset=utf-8' })) // 打开新页签 预览pdf const wo = window.open(href) // 设置title let timer = setInterval(() => { if (wo.closed) { clearInterval(timer) } else { wo.document.title = docTitle } }, 500) } /** * 文件下载 * @param {File} blob * @param {string} filename */ export function download(blob, filename = 'WFT.xlsx') { const link = document.createElement('a') const URL = window.URL || window.webkitURL; const href = URL.createObjectURL(new Blob([blob])) link.href = href link.download = filename document.body.appendChild(link) link.click() document.body.removeChild(link) // URL.revokeObjectURL(href) // 释放掉blob对象 } /** * 从视频文件中提取一帧图片 * @param {Blob} vdoFile 视频文件 * @param {number} time 秒数 * @returns */ export function captureFrame(vdoFile, time = 0) { return new Promise((resolve, reject) => { try { const video = document.createElement('video'); video.currentTime = time; video.muted = true; video.autoplay = true; video.src = URL.createObjectURL(vdoFile); video.oncanplay = () => { const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); canvas.toBlob(blob => { const url = URL.createObjectURL(blob) resolve({ blob, url }) }, 'image/jpeg', 0.8) } } catch (error) { reject(error) } }) } /** * 防抖 * @param {Function} fn * @param {Number} wait * @param {Boolean} immediate * @returns */ export function debounce(fn, wait, immediate = false) { let timer = null let isInvoke = false function _debounce() { return new Promise((resolve, reject) => { try { if (timer) clearTimeout(timer) // 第一次操作是否不需要延迟、立即执行 let res = undefined if (immediate && !isInvoke) { res = fn.apply(this, Array.from(arguments)) resolve(res) isInvoke = true return } // 延迟执行 timer = setTimeout(() => { res = fn.apply(this, Array.from(arguments)) resolve(res) timer = null isInvoke = false }, wait) } catch (error) { reject(error) } }) } // 取消功能 _debounce.cancel = function () { if (timer) clearTimeout(timer) timer = null isInvoke = false } return _debounce } /** * 节流 * @param {Function} fn * @param {Number} wait * @returns */ export function throttle(fn, wait) { let timer = null return function () { if (!timer) { fn.apply(this, Array.from(arguments)) timer = setTimeout(() => { timer = null }, wait) } } } /** * 使用代理创建单例 * @param {Function | class} className * @returns */ export function singleton(className) { let instance = null; const proxy = new Proxy(className, { construct(_target, args) { if (!instance) { instance = new className(...args) } else { console.warn(`${className}只有一个实例.`) } return instance; } }) className.prototype.constructor = proxy; return proxy; } /** * 自动转化柯里化过程 * @param {Function} fn * @returns */ export function ftCurrying(fn) { function curryingFn(...args) { if (args.length >= fn.length) { return fn.apply(this, args) } else { return function (...nextArgs) { return curryingFn.apply(this, [...args, ...nextArgs]) } } } return curryingFn } /** * 创建数组迭代器 * @param {Array | string} arr * @returns */ export function createArrayIterator(arr) { let index = 0 return { next() { if (index < arr.length) { return { done: false, value: arr[index++] } } else { return { done: true, value: undefined } } } } } /** * 创建数组生成器 * @param {Array | string} arr */ export function* createArrayGenerator(arr) { yield* arr } /** * 生成uuid * @returns */ export function getUuid() { const temp_url = URL.createObjectURL(new Blob()) const uuid = temp_url.toString() URL.revokeObjectURL(temp_url) //释放这个url return uuid.substring(uuid.lastIndexOf('/') + 1) } /** * 生成uuid * @returns */ export function generateUUID() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); } /** * 生成随机字符串(长度通常在5-11个字符之间) * @returns */ export function getRandomStr() { return Math.random().toString(36).slice(2) } /** * base64编码转Blob * @param {string} base64Data * @returns */ export function base64ToBlob(base64Data) { let arr = base64Data.split(','), fileType = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), l = bstr.length, u8Arr = new Uint8Array(l); while (l--) { u8Arr[l] = bstr.charCodeAt(l); } return new Blob([u8Arr], { type: fileType }); } /** * 根据身份证号获取年龄 * @param {String} idCard */ export function getAgeFromID(idCard) { // 检查身份证号是否合法 if (!/^\d{17}[\dXx]$/.test(idCard)) { return; } // 获取出生日期 let year = parseInt(idCard.substring(6, 10), 10); let month = parseInt(idCard.substring(10, 12), 10); let day = parseInt(idCard.substring(12, 14), 10); // 创建出生日期对象 let birthDate = new Date(year, month - 1, day); // 获取当前日期 let today = new Date(); // 计算年龄 let age = today.getFullYear() - birthDate.getFullYear(); let monthDiff = today.getMonth() - birthDate.getMonth(); // 如果月份或日期还未到达,则年龄减一 if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } return age; } /** * 根据身份证号获取性别 * @param {String} idCard */ export function getGenderFromID(idCard) { // 验证身份证号是否合法 if (!/^\d{17}[\dXx]$/.test(idCard)) { return null; } // 提取第17位数字 const genderDigit = parseInt(idCard.charAt(16), 10); if (isNaN(genderDigit)) { return null; } // 判断性别 if (genderDigit % 2 === 0) { return "女"; } else { return "男"; } } /** * 解析路径中的参数 * @param {string} url * @returns */ export function getQueryParamsFromUrl(url) { if (!url || typeof url !== 'string') { return {} } const urlParse = queryString => { const urlObj = new URL(queryString); const params = new URLSearchParams(urlObj.search); const result = {}; for (const [key, value] of params.entries()) { result[key] = value; } return result; } const regexParse = queryString => { const result = {}; const regex = /([^?&=]+)=([^&]*)/g; // 匹配 key=value 形式的键值对 let match; while ((match = regex.exec(queryString)) !== null) { const key = decodeURIComponent(match[1]); const value = decodeURIComponent(match[2]); result[key] = value; } return result; } if (window.URL && window.URLSearchParams) { return urlParse(url) } return regexParse(url) } /** * 判断手机是Andoird还是IOS * @returns */ export function getOSType() { let u = navigator.userAgent; let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); if (isIOS) return 1; if (isAndroid) return 2; return 3; } /** * 手机号脱敏 * @param {string} mobile * @returns */ export function hideMobile(mobile) { return mobile.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2") } /** * 驼峰转下划线 * @param {string} name * @returns */ export function hump2Line(name) { if (name.indexOf('.') < 0) { return name.replace(/([A-Z])/g, '_$1').toLowerCase() } else { return name } } /** * 下划线转驼峰 * @param {string} str * @returns */ export function line2Hump(str) { return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase()) } /** * 创建html字符串 * @param {HTMLElement} node * @returns */ export function createHtmlStr(node) { const div = document.createElement('div') div.appendChild(node) return div.innerHTML } /** * html转文本 * @param {string} val * @returns */ export function html2Text(val) { const div = document.createElement('div') div.innerHTML = val return div.textContent || div.innerText } /** * 复制文本到剪切板 * @param {string} text * @returns */ export function copyText(text) { return new Promise((resolve, reject) => { if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(resolve, reject) } else { const textArea = document.createElement('textarea') textArea.value = text textArea.style.opacity = '0' document.body.appendChild(textArea) textArea.select() // 复制文本 try { document.execCommand('copy'); resolve(undefined) } catch (err) { reject(err) } document.body.removeChild(textArea) } }) } /** * 检验数据类型 * @param {any} obj * @returns */ export function getObjType(obj) { let toString = Object.prototype.toString let map = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object AsyncFunction]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regExp', '[object Undefined]': 'undefined', '[object Null]': 'null', '[object Object]': 'object' } if (obj instanceof Element) { return 'element' } return map[toString.call(obj)] } /** * 转树形数据 * @param {*} data list数据 * @param {*} id 主键ID * @param {*} pid 上级ID * @param childrenKey 子list数据的key */ export function treeDataTranslate(data, id = 'id', pid = 'parentId', childrenKey = 'children') { let res = [] let temp = {} for (let i = 0; i < data.length; i++) { temp[data[i][id]] = data[i] } for (let k = 0; k < data.length; k++) { if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) { if (!temp[data[k][pid]][childrenKey]) { temp[data[k][pid]][childrenKey] = [] } if (!temp[data[k][pid]]['_level']) { temp[data[k][pid]]['_level'] = 1 } data[k]['_level'] = temp[data[k][pid]]._level + 1 temp[data[k][pid]][childrenKey].push(data[k]) } else { res.push(data[k]) } } return res } /** * 转树形结构 * @param {Array} list list数据 * @param {string} id 主键ID * @param {string} pid 上级ID * @param {string} childrenKey 标识子节点的key * @returns */ export function toTree(list, id = 'id', pid = 'parentId', childrenKey = 'children') { const target = [] const map = {} list.forEach(item => { map[item[id]] = item }) list.forEach(item => { let parent = map[item[pid]] if (parent) { (parent[childrenKey] || (parent[childrenKey] = [])).push(item) } else { target.push(item) } }) return target } /** * 遍历树形数据 * @param {*} treeData 树形数据 * @param {*} callback 每次遍历的回调函数 * @param {*} childrenKey 树形数据中标识子节点的字段 * @param {*} level 级别 */ export function mapTree(treeData, callback, childrenKey = 'children', level = 0) { treeData.forEach(item => { const curItem = JSON.parse(JSON.stringify(item)) curItem.level = level callback(curItem, treeData) if (item?.[childrenKey]?.length) { mapTree(item[childrenKey], callback, childrenKey, level + 1) } }) } /** * 扁平树形(广度优先遍历) * @param {*} root 根节点<Object> * @returns */ export function bfsFlatTree(root) { const target = [] const arr = [root] for (let item of arr) { const o = JSON.parse(JSON.stringify(item)) if (o.children) delete o.children target.push(o) if (item.children && item.children.length) { item.children.forEach(ele => { arr.push(ele) }) } } return target } /** * 树形结构根据里层ID找出所属父级集合 */ export class FindParents { constructor({ tree, id, idKey = 'id', parentIdKey = 'parentId', childrenKey = 'children', rootId = '0' }) { this.idKey = idKey this.parentIdKey = parentIdKey this.childrenKey = childrenKey this.rootId = rootId this.flatList = this.flatTree(tree) this.parents = this.getParents(id, this.flatList) this.getParentValuesByKey.bind(this) } flatTree(tree) { // 扁平树型(深度遍历) const target = [] tree.forEach(item => { const cloneItem = JSON.parse(JSON.stringify(item)) if (cloneItem[this.childrenKey]) delete cloneItem[this.childrenKey] target.push(cloneItem) if (item[this.childrenKey] && item[this.childrenKey].length) { target.push(...this.flatTree(item[this.childrenKey])) } }) return target } getParents(id, list) { const target = [] const data = list.find(item => item[this.idKey] === id) if (data === undefined) return target target.push(data) if (data[this.parentIdKey] !== this.rootId) { target.push(...this.getParents(data[this.parentIdKey], list)) } return target } getParentValuesByKey(key) { return this.parents.map(item => item[key]).reverse() } } /** * 树形结构根据里层ID找出所属父级集合 */ export class FindArrsById { constructor(id, tree) { this.id = id this.flatList = this.flatTreeAndSetLevel.call(this, tree) this.parents = this.getParents.call(this, id, this.flatList) this.getParentValuesByKey.bind(this) } flatTreeAndSetLevel(tree, level = 0) { // 扁平树型(深度遍历) const target = [] tree.forEach(item => { const o = JSON.parse(JSON.stringify(item)) if (o.children) delete o.children o.level = level target.push(o) if (item.children && item.children.length) { target.push(...this.flatTreeAndSetLevel(item.children, level + 1)) } }) return target } getParents(id, list) { const target = [] const o = list.find(item => item.id === id) || {} if (JSON.stringify(o) !== '{}') target.push(o) if (o.parentId) target.push(...this.getParents(o.parentId, list)) return target } getParentValuesByKey(key) { return this.parents.map(item => item[key]).reverse() } } /** * 对象去重 * @param {*} obj * @returns */ export function noRepeatObj(obj) { if (obj.constructor !== Object) return {} const target = {} for (let key in obj) { let flag = true for (let k in target) { if (JSON.stringify(target[k]) === JSON.stringify(obj[key])) { flag = false } } if (flag) { target[key] = obj[key] } } return target } /** * 数组去重 * @param {*} list * @returns */ export function noRepeatArr(list) { if (list.every(item => typeof item !== 'object')) { return [...new Set(list)] } return [...new Set(list.map(item => JSON.stringify(item)))].map(item => JSON.parse(item)) } /** * 对象数组,根据某个字段去重 例如: [ { id: 0, name: 'wft1' }, { id: 0, name: 'wft_1' }, { id: 1, name: 'wft2' } ] * @param {*} list * @param {*} field */ export function noRepeatArrByField(list, field = 'id') { const map = {} list.forEach(item => { if (!map[item[field]]) { map[item[field]] = item } }) return Object.values(map) } /** * 数组去重 * 两个属性相同的对象 也认为是重复的 * 这里采用原始的处理方式去重(当然如果是引用类型的话可以通过JSON.stringify转为json字符串 然后通过ES6中的Set去重) * @param {Array} arr */ export function uniqueArray(arr) { const target = [] for (let i = 0; i < arr.length; i++) { let flag = true for (let j = 0; j < target.length; j++) { if (equals(arr[i], target[j])) { flag = false break } } if (flag) { target.push(arr[i]) } } return target } /** * 比较两个值是否相等(两个属性相同的对象 也认为是重复的) * @param {*} value1 * @param {*} value2 */ function equals(value1, value2) { if (isBasicType(value1) || isBasicType(value2)) { return Object.is(value1, value2) } if (Object.keys(value1).length !== Object.keys(value2).length) { return false } for (let key in value1) { if (!equals(value1[key], value2[key])) { return false } } return true } /** * 判断是否是基本数据类型(这里null虽然是object类型,但也可以直接通过Object.is判断相等,所以暂认为基本类型) * @param {*} value * @returns */ function isBasicType(value) { const referenceType = ['object', 'function'] return !referenceType.includes(typeof value) || value === null } /** * 千分位数字转换 * @param {*} value * @returns */ export function numberToCurrencyNo(value) { if (!value) return '0' if (value === '--') return '--' value = value - 0 // 将数值截取,保留0位小数 value = value.toFixed(0) // 获取整数部分 const intPart = Math.trunc(value) // 整数部分处理,增加, const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') // 预定义小数部分 let floatPart = '' // 将数值截取为小数部分和整数部分 const valueArray = value.toString().split('.') if (valueArray.length === 2) { // 有小数部分 floatPart = valueArray[1].toString() // 取得小数部分 return intPartFormat + '.' + floatPart } return intPartFormat + floatPart } /** * 表单对象赋值: * 对目标对象存在且源对象同样存在的属性,全部覆盖; * 目标对象不存在但是源对象存在的属性, 全部丢弃; * 目标对象存在但是源对象不存在的属性,如果是字符串赋值为空串,其余类型赋值为undefined * @param {Object} target * @param {Object} source * @returns */ export function recover(target, source) { if (target === undefined || target === null) { throw new TypeError('Cannot convert first argument to object') } var to = Object(target) if (source === undefined || source === null) { return to } var keysArray = Object.keys(Object(target)) for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex] var desc = Object.getOwnPropertyDescriptor(target, nextKey) if (desc !== undefined && desc.enumerable) { if (to.hasOwnProperty(nextKey)) { if (to[nextKey] instanceof Array) { to[nextKey] = source[nextKey] } else if (to[nextKey] instanceof Object) { recover(to[nextKey], source[nextKey]) } else if (source[nextKey] !== undefined) { to[nextKey] = source[nextKey] } else if (typeof (to[nextKey]) === 'string') { to[nextKey] = '' } else { to[nextKey] = undefined } } } } return to } /** * 表单对象赋值: * 对目标对象存在且源对象同样存在的属性,全部覆盖; * 目标对象不存在但是源对象存在的属性, 全部丢弃; * 目标对象存在但是源对象不存在的属性,保留目标对象的属性不做处理 * @param {Object} target * @param {Object} source * @returns */ export function recoverNotNull(target, source) { if (target === undefined || target === null) { throw new TypeError('Cannot convert first argument to object') } var to = Object(target) if (source === undefined || source === null) { return to } var keysArray = Object.keys(Object(target)) for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex] var desc = Object.getOwnPropertyDescriptor(target, nextKey) if (desc !== undefined && desc.enumerable) { if (to.hasOwnProperty(nextKey)) { if (to[nextKey] instanceof Array) { to[nextKey] = source[nextKey] } else if (to[nextKey] instanceof Object) { recover(to[nextKey], source[nextKey]) } else if (source[nextKey] !== undefined) { to[nextKey] = source[nextKey] } } } } return to } /** * 判断一个指定的位置点坐标是否落在一个多边形区域内 * @param {number} aLon 经度 * @param {number} aLat 维度 * @param {Array<{ longitude: number, latitude: number }>} pointList 多边形坐标集合(多边形点的顺序需根据顺时针或逆时针,不能乱) * @returns */ export function isPtInPoly(aLon, aLat, pointList) { let iSum = 0 let iCount = pointList.length if (iCount < 3) { return false } // 待判断的点(x, y) 为已知值 let y = aLat let x = aLon for (let i = 0; i < iCount; i++) { let x1 = pointList[i].longitude let y1 = pointList[i].latitude let x2, y2 if (i == iCount - 1) { x2 = pointList[0].longitude y2 = pointList[0].latitude } else { y2 = pointList[i + 1].latitude x2 = pointList[i + 1].longitude } // 当前边的 2 个端点分别为 已知值(x1, y1), (x2, y2) if (((y >= y1) && (y < y2)) || ((y >= y2) && (y < y1))) { // y 界于 y1 和 y2 之间 // 假设过待判断点(x, y)的水平直线和当前边的交点为(x_intersect, y_intersect),有y_intersect = y // 则有(2个相似三角形,公用顶角,宽/宽 = 高/高):|x1 - x2| / |x1 - x_intersect| = |y1 - y2| / |y1 - y| if (Math.abs(y1 - y2) > 0) { let x_intersect = x1 - ((x1 - x2) * (y1 - y)) / (y1 - y2); if (x_intersect < x) { iSum += 1 } } } } if (iSum % 2 != 0) { return true } else { return false } } /** * 字符串大小写转换 * 1: 转大写;2:转小写;3:首字母大写 * @param {string} str * @param {number} type * @returns */ export function turnCase(str, type) { switch (type) { case 1: return str.toUpperCase(); case 2: return str.toLowerCase(); case 3: return str[0].toUpperCase() + str.slice(1).toLowerCase(); default: return str; } } /** * echarts字体自适应方法,px -> rem * @param {*} res * @returns */ export function fontChart(res) { let docEl = document.documentElement, clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; if (!clientWidth) return; // 此处的3840 为设计稿的宽度,记得修改! let fontSize = clientWidth / 1920; return res * fontSize; } /** * 序列化(JSON.stringify对象序列化,解决undefined、函数和NaN 丢失问题) * @param {*} option * @returns */ export function JSONStringify(option) { return JSON.stringify(option, (key, val) => { // 处理函数丢失问题 if (typeof val === 'function') { return `${val}`; } // 处理undefined丢失问题 if (typeof val === 'undefined') { return 'undefined'; } // 处理NaN转为null的情况(注意: 这里如果使用isNaN的话,那么对象也会走进去) if (val !== val) { return `${val}` } return val; }, 2) } /** * 反序列化(重写扩展JSON.parse方法) * @param {*} jsonStr * @returns */ export function JSONParse(jsonStr) { return JSON.parse(jsonStr, (_key, val) => { let isRetain = false if (typeof val === 'string') { isRetain = val.indexOf('function') >= 0 || val === 'undefined' || val === 'NaN' } if (isRetain) { // eslint-disable-next-line return eval(`(function(){return ${val}})()`); } return val }) } /** * 打开小窗口 * @param {string} url * @param {string} title * @param {number} w * @param {number} h * @returns */ export function openWindow(url, title, w, h) { const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top; const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; const left = width / 2 - w / 2 + dualScreenLeft; const top = height / 2 - h / 2 + dualScreenTop; return window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left); } /** * Storage存储 */ export class StorageCache { #storage = null constructor(isLocal = true) { this.#storage = isLocal ? window.localStorage : window.sessionStorage } setCache(key, value) { const dataType = typeof value const dateTime = new Date().getTime() const obj = { value, dataType, dateTime } this.#storage.setItem(key, JSON.stringify(obj)) } getCache(key) { const result = this.#storage.getItem(key) return result ? JSON.parse(result).value : result } getAllCache() { const list = [] for (let i = 0; i < this.#storage.length; i++) { const curKey = this.#storage.key(i) list.push({ key: curKey, value: this.getCache(curKey) }) } return list } removeCache(key) { this.#storage.removeItem(key) } clear() { this.#storage.clear() } } /** * sessionStorage工具方法 */ export class SessionUtils { static get(key) { return JSON.parse(window.sessionStorage.getItem(key)) } static set(key, value) { window.sessionStorage.setItem(key, JSON.stringify(value)) } static remove(key) { window.sessionStorage.removeItem(key) } static clear() { window.sessionStorage.clear() } static getAll() { const list = [] for (let i = 0; i < window.sessionStorage.length; i++) { const curKey = window.sessionStorage.key(i) list.push({ key: curKey, value: SessionUtils.get(curKey) }) } return list } } /** * localStorage工具方法 */ export class LocalUtils { static get(key) { return JSON.parse(window.localStorage.getItem(key)) } static set(key, value) { window.localStorage.setItem(key, JSON.stringify(value)) } static remove(key) { window.localStorage.removeItem(key) } static clear() { window.localStorage.clear() } static getAll() { const list = [] for (let i = 0; i < window.localStorage.length; i++) { const curKey = window.localStorage.key(i) list.push({ key: curKey, value: LocalUtils.get(curKey) }) } return list } } /** * 使用JS完成一个LRU缓存 * 超出内存将淘汰掉最近最少使用的页面 */ export class LRUCache { #length = null #map = null constructor(length) { this.#length = length // 存储长度 this.#map = new Map() // 存储数据 } // 存储数据,通过键值对的方式 set(key, value) { if (this.#map.has(key)) { this.#map.delete(key) } this.#map.set(key, value) // 如果超出了容量,则删除最久的数据(map中即第一个) if (this.#map.size > this.#length) { this.#map.delete(this.#map.keys().next().value) } } // 获取数据 get(key) { if (!this.#map.has(key)) { return null } const val = this.#map.get(key) // 获取元素 this.#map.delete(key) // 删除元素 this.#map.set(key, val) // 重新插入元素,更新存储顺序 } }