/**
* 精确类型判断
* @param {String} value 需要判断类型的数据
* @return {String} null undefined number string boolean function array date regexp object symbol
*/
export function checkType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
/**
* 深度冻结对象
* @param {Object} obj 需要冻结的对象
* @return {Object} obj 冻结后的对象
*/
export function deepFreeze(obj) {
const propNames = Object.getOwnPropertyNames(obj)
propNames.forEach((name) => {
const prop = obj[name]
if (typeof prop === 'object' && prop !== null) deepFreeze(prop)
})
return Object.freeze(obj)
}
/**
* 数据深拷贝
* @param {Any} date 需要拷贝的数据
* @return {Any} newData 拷贝的数据
*/
export const deepClone = (data, hash = new WeakMap()) => {
if (typeof data !== 'object' || data === null) {
throw new TypeError('传入参数不是对象')
}
// 判断传入的待拷贝对象的引用是否存在于hash中
if (hash.has(data)) {
return hash.get(data)
}
let newData = {};
const dataKeys = Object.keys(data);
dataKeys.forEach(key => {
const currentData = data[key];
// 基本数据类型的值和函数直接赋值拷贝
if (typeof currentData !== "object" || currentData === null) {
newData[key] = currentData;
} else if (Array.isArray(currentData)) {
// 实现数组的深拷贝
newData[key] = [...currentData];
} else if (currentData instanceof Set) {
// 实现set数据的深拷贝
newData[key] = new Set([...currentData]);
} else if (currentData instanceof Map) {
// 实现map数据的深拷贝
newData[key] = new Map([...currentData]);
} else {
// 将这个待拷贝对象的引用存于hash中
hash.set(data, data)
// 普通对象则递归赋值
newData[key] = deepClone(currentData, hash);
}
})
return newData;
}
/**
* 数组转树结构
* @param {Array} array 需要处理为树形结构的数组
* @param {String} id 数据id
* @param {String} pid 数据的父id
* @param {String} children 子数据存储位置
* @return {Array} result 处理成树结构的数据
*/
export function arrayToTree(array, id = 'id', pid = 'pid', children = 'children') {
let data = {}
try {
data = JSON.parse(JSON.stringify(array))
} catch (e) {
console.error('克隆失败!')
}
const result = []
const hash = {}
if (data && data.length > 0) {
data.forEach((item, index) => {
hash[data[index][id]] = data[index]
})
}
if (data && data.length > 0) {
data.forEach(item => {
const hashVP = hash[item[pid]]
if (hashVP) {
!hashVP[children] && (hashVP[children] = [])
hashVP[children].push(item)
} else {
result.push(item)
}
})
}
return result
}
/**
* 树结构转数组
* @param {Array} tree 树形数据
* @param {Function} fn 树结构数据转数组过程中可传入数据处理函数
* @param {String} children 树行数据key
* @return {Array} data 处理成数组的数据
*/
export function treeToArray(tree, fn, children = 'children', data = []) {
for (const item of tree) {
let newItem = item
if (typeof fn === "function") {
newItem = fn(newItem)
}
data.push(newItem)
if (newItem[children]) {
treeToArray(newItem[children], fn, children, data)
}
}
return data
}
/**
* 生成UUID
* @param {Number} len 控制UUID长度
* @param {Number} radix uuid基数
* @return {String} uuid 生成的UUID
*/
export function uuid(len, radix) {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
const uuid = []
radix = radix || chars.length
if (len) {
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
} else {
let r
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
uuid[14] = '4'
for (let n = 0; n < 36; n++) {
if (!uuid[n]) {
r = 0 | Math.random() * 16
uuid[n] = chars[(n === 19) ? (r & 0x3) | 0x8 : r]
}
}
}
return uuid.join('')
}
/**
* 获取网页可见区域宽高
* @return {Object} width 可见区域宽度 height可见区域高度
*/
export function getWindowSize() {
/*
document.body.clientWidth 网页可见区域宽
document.body.clientHeight 网页可见区域高
document.body.offsetWeight 网页可见区域高(包括边线的宽)
document.body.offsetHeight 网页可见区域高(包括边线的宽)
document.body.scrollWidth 网页正文全文宽
document.body.scrollHeight 网页正文全文高
document.body.scrollTop 网页被卷去的高
document.body.scrollLeft 网页被卷去的左
window.screenTop 网页正文部分上
window.screenLeft 网页正文部分左
window.screen.height 屏幕分辨率的高
window.screen.width 屏幕分辨率的宽
window.screen.availHeight 屏幕可用工作区高度
window.screen.availWidth 屏幕可用工作区宽度
*/
const width = document.documentElement.clientWidth || document.body.clientWidth
const height = document.documentElement.clientHeight || document.body.clientHeight
return { width, height }
}
/**
* 存储移除token
* @param {String} key 操作token的key
* @param {String} token token数据-不传则清空
* @return {String} token
*/
export function setToken(key = 'token', token) {
if (token) {
sessionStorage.setItem(key, token)
} else {
sessionStorage.removeItem(key)
}
}
/**
* 读取token
* @param {String} key 读取token的key
* @return {String} token
*/
export function getToken(key = 'token') {
return sessionStorage.getItem(key)
}
/**
* 设置网站图标
* @param {String} link 需要更换图标的url
*/
export function setFavicon(link) {
const favicon = document.querySelector("link[rel*='icon']") || document.createElement('link')
favicon.type = 'image/x-icon'
favicon.rel = 'shortcut icon'
favicon.href = link
document.getElementsByTagName('head')[0].appendChild(favicon)
}
/**
* node判断是否生产环境
* @return {Boolean}
*/
export function isProd() {
return process.env.NODE_ENV === 'production' ? true : false
}
/**
* 防抖 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
* 立即执行:多次触发事件,第一次会立即执行函数,之后在设定wait时间内触犯的事件无效,不会执行
* 非立即执行函数:多次触发事件,只会在最后一次触发事件后等待设定的wait时间结束时执行一次
* @param {Function} func 需要防抖的函数
* @param {Number} wait 防抖时间
* @param {Boolean} immediate 是否立即执行
*/
export const debounce = function (func, wait, immediate) {
let timer = null
return function () {
const args = arguments
if (immediate) {
// 立即执行
const callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
//timer为null执行func函数
if (callNow) func.apply(this, args)
} else {
// 非立即执行
timer = setTimeout(() => {
func.apply(this, args)
}, wait);
}
}
}
/**
* 节流 连续触发事件但是在 n 秒中只执行一次函数
* @param {Function} func 需要节流的函数
* @param {Number} delay 节流时间
*/
export const throttle = function (func, delay) {
let timer = null
return function () {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, arguments)
timer = null
}, delay)
}
}
}
/**
* 金额格式化逢三断一保留两位小数
* @param {Number} monery 金额
* @return {String} 格式化后的金额
*/
export const moneyFormat = function (monery) {
if (checkType(monery) === 'string' || checkType(monery) === 'number') {
if (isNaN(monery)) {
// 提示处理异常
return '-'
}
let intPart = monery | 0 //获取整数部分(此方法不能处理超过32位的数值取整)
let floatPart = monery.toFixed(2).toString().split(".")[1] //取小数部分
let intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') //将整数部分逢三一断
return intPartFormat + '.' + floatPart
} else {
// 提示传入参数错误
return '-'
}
}
/**
* 计算文件大小
* @param {Number} byte 文件byte
* @return {String} 计算后文件大小
*/
export const formatSize = function (byte) {
if (!byte) {
return '-'
}
let value = 0
// 单位集合
const suffix = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
// 自然对数反推幂
const power = Math.log(byte) / Math.LN2
// 算出幂的因数,并向下取整,同时用作取出单位
const powerBase = Math.floor(power / 10)
// 算出换算后的单位了
value = byte / Math.pow(2, powerBase * 10)
// 省略小数点
value = +(value).toFixed(2)
// 逢三一断
return `${value.toString().replace(/(\\d)(?=(?:\\d{3})+$)/g, '$1,')}${suffix[powerBase]}`
}
/**
* 控制台抛出提示信息
* @param {String} title 标题
* @param {String} content 详情
*/
export function cTip(title = '', content = '') {
console.info(
`%c ${'[TIP]'} %c ${title}${content ? '↓↓↓\n' : ''}`,
'background: #ff4d4f;color: #ffffff;border-top-left-radius: 3px;border-bottom-left-radius: 3px;padding: 0;',
'background: #35495E;color: #ffffff;border-top-right-radius: 3px;border-bottom-right-radius: 3px;padding-right: 10px;', content)
}
/**
* 首字母转大写
* @param {String} str 字符串
*/
export const firstToUpper = str => {
return str.replace(str[0], str[0].toUpperCase())
}
/**
* 首字母转小写
* @param {String} str 字符串
*/
export const firstToLower = str => {
return str.replace(str[0], str[0].toLowerCase())
}
/**
* 字符串转base64
* @param {String} str 字符串
*/
export function encodeStr(str) {
const encode = encodeURI(str);//编码
const base64 = window.btoa(encode);//转Base64
return base64;
}
/**
* base64转字符串
* @param {String} str 字符串
*/
export function decodeStr(base64) {
const decode = window.atob(base64);//Base64反转
const str = decodeURI(decode);//解码
return str;
}
/**
* 下载
* originalAxios 为原始的axios,使用时视axios封装情况和后端返回数据情况对此函数进行修改
* @param {Object} url 请求的地址 data 请求携带的参数
*/
export function getFileBlob({ url = '', data = {} }) {
// eslint-disable-next-line no-undef
originalAxios({ url, method: 'post', responseType: 'blob', data })
.then((res) => {
if (res.status === 200) {
const resData = res.data
const fileReader = new FileReader()
fileReader.onloadend = () => {
try {
const jsonData = JSON.parse(fileReader.result)
console.log('报错信息', jsonData)
// TODO:提示报错信息,信息在jsonData内
} catch (err) {
// 解析成对象失败,说明是正常的文件流
let fileName = ''
try {
fileName = decodeURIComponent(res.headers['content-disposition'].split(';')[1].split('filename=')[1])
downloadFile(resData, fileName)
} catch {
// 如果获取不到文件名则自动生成,此处根据具体需求处理文件后缀
fileName = new Date().getTime() + 'xlsx'
downloadFile(resData, fileName)
}
}
}
fileReader.readAsText(resData)
} else {
// TODO:提示报错信息
}
})
.catch((err) => {
// TODO:提示报错信息
})
}
/**
* 下载文件
* @param {Blob} response 后端返回的流
* @param {String} fileName 文件名(需要带文件类型后缀)
*/
export function downloadFile(response, fileName) {
if (window.navigator.msSaveOrOpenBlob) {
// ie特有下载
navigator.msSaveBlob(response, `${response.filename ? response.filename : fileName}`)
} else {
const link = document.createElement('a')
link.href = window.URL.createObjectURL(response)
link.download = response.filename ? response.filename : `${fileName}`
link.click()
window.URL.revokeObjectURL(link.href)
}
}
js常用工具函数总结
最新推荐文章于 2022-04-10 17:10:35 发布