js常用工具函数总结

/**
 * 精确类型判断
 * @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)
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值