前端日常工作中会用到的一些函数

105 阅读3分钟

大家好,我是鹿萌萌,总结一下在我工作中用过的非常实用的一些工具函数

喜欢萌萌的欢迎一键三连💗💗💗

判断是否为空

export const isEmpty = target => {
    // '' null undefined 0
    if (!target) {
        return true;
    }
    // 空数组
    if (Array.prototype.isPrototypeOf(target) && target.length === 0) {
        return true;
    }
    // 空对象
    if ((Object.prototype.isPrototypeOf(target)) && (Object.keys(target).length === 0)) {
        return true;
    }
    return false;
};

时间戳转为日期

export function timestampToTime(timestamp) {
    const date = new Date(timestamp * 1000);// 时间戳为10位需*1000,时间戳为13位的话不需乘1000
    const Y = date.getFullYear() + '-';
    const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
    const D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
    const h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
    const m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
    const s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
    return Y + M + D + h + m + s;
}

将a=1&b=2 这种querystring转为object

export const querystringToObj = (string) => {
    const obj = {};
    string.split('&').forEach(item => {
        const [key, value] = item.split('=');
        obj[key] = value;
    });
    return obj;
};

获取url某个参数的值

export const getUrlParam = name => {
    let reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i');
    let r = window.location.search.substr(1).match(reg);
    if (r !== null) {
        return r[2];
    }
    return '';
};

使用:const param = getUrlParam('param') || ''

获取base64

export const getBase64 = (file: any) => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
    });
};

字符串截取拼接...

export const formatName = (value, num) => {
    if (!value) {
        return '';
    }
    if (value.length > num) {
        let strArr = Array.from(String(value));
        value = strArr.slice(0, num).join('') + '...';
        return value;
    }
    return value;
};

多个参数拼接起来

// object 转 str for url
export const buildParam = data => {
    if (typeof data === 'object') {
        return Object.keys(data)
            .map(key => {
                let value = data[key] === undefined ? '' : encodeURIComponent(data[key]);
                return `${key}=${value}`;
            })
            .join('&');
    }
    return '';
};
// 使用
const options = {
    param: 'param'
};
const protocol = window.location.protocol || 'https:';
const path = `${protocol}//www.baidu.com`;
const url = `${path}/index.html?${buildParam(options)}`;

数据处理

export function toFixed(num: number) {
    // toFixed原生函数会四舍五入
    const [n1, n2] = `${num}`.split('.');
    return `${n1}${n2 ? `.${n2.slice(0, 1)}` : '.0'}`;
}

export function formatVal(number?: string | number) {
    const num = number ? +number : 0;
    if (num > 99999999) {
        return toFixed(num / 100000000) + '亿';
    }
    if (num > 9999999) {
        return toFixed(num / 10000000) + 'kw';
    }
    if (num > 9999) {
        return toFixed(num / 10000) + 'w';
    }
    return num;
}

// 保留2位小数(不够位数,则用0替补)
export function keepTwoDecimalFull(num: number) {
    let result = parseFloat(String(num));
    if (isNaN(result)) {
        return false;
    }
    result = Math.round(num * 100) / 100;
    let s_x = result.toString(); // 将数字转换为字符串
    let pos_decimal = s_x.toString().indexOf('.'); // 小数点的索引值
    // 当整数时,pos_decimal=-1 自动补0
    if (pos_decimal < 0) {
        pos_decimal = s_x.length;
        s_x += '.';
    }
    // 当数字的长度< 小数点索引+2时,补0
    while (s_x.length <= pos_decimal + 2) {
        s_x += '0';
    }
    return s_x;
}
/**
 * @method 数字金额中间加上逗号
 * @param {number | string} index
 * @returns string
 */
export const moneyFormat = item => {
    let num = (item || 0).toString();
    let result = '';
    while (num.length > 3) {
        result = `,${num.slice(-3)}${result}`;
        num = num.slice(0, num.length - 3);
    }
    if (num) {
        result = num + result;
    }
    return result;
};

时间格式处理

const formatTime = (z: number, type = 1) => {
    let time = new Date(z * 1000);
    let Month = String(time.getMonth() + 1);
    let Day = String(time.getDate());
    let Hour = String(time.getHours());
    let Minute = String(time.getMinutes());
    if (String(Month).length === 1) {
        Month = '0' + Month;
    }
    if (String(Day).length === 1) {
        Day = '0' + Day;
    }
    if (String(Hour).length === 1) {
        Hour = '0' + Hour;
    }
    if (String(Minute).length === 1) {
        Minute = '0' + Minute;
    }
    let timeValue = null;
    if (type === 0) {
        return [Month, Day, Hour, Minute];
    }
    switch (type) {
        case 0:
            timeValue = [Month, Day, Hour, Minute];
            break;
        case 1:
            timeValue = `${Month}${Day}${Hour}:${Minute}`;
            break;
        case 2:
            timeValue = `${Hour}:${Minute}`;
            break;
        case 3:
            timeValue = `${Month}${Day}${Hour}:${Minute}`;
            break;
        case 4:
            timeValue = `${Month}${Day}${Hour}:${Minute}`;
            break;
        default:
            break;
    }
    return timeValue;
};

export const showInfoLiveTime = (live_start_time: number, live_end_time: number) => {
    let start = formatTime(live_start_time, 4);
    let end = formatTime(live_end_time, 4);
    return `${start}  -  ${end}`;
};

storag get/set

/**
 * @param key 要获取的localStorage key
 * @returns {*} parse过的storage值
 */
export function getStorage(key) {
    let res = window.localStorage.getItem(key);

    try {
        res = JSON.parse(res);
    } catch (e) {
        // 返回值非json字符串,不处理,直接返回
    }

    return res;
}

/**
 * @param key 要添加/更新的localStorage key
 * @param value 要添加/更新的localStorage 值
 */
export function setStorage(key, value) {
    let parsedValue = value;

    if (typeof value !== 'string') {
        parsedValue = JSON.stringify(value);
    }
    window.localStorage.setItem(key, parsedValue);
}

星星展示

/**
 * 星级转换 例如4.5转换成[1, 1, 1, 1, 0.5, 0],用于渲染星级icon
 * @params {Number} 星级分数
 * @return {Array} 星级数组长度
 */
export const handleStar = (numParam, len = 5) => {
    const num = Number(numParam);
    if (typeof num !== 'number') {
        return [];
    }

    const lower = Math.floor(num);
    let arr = Array.from({length: len}, (v, idx) => {
        if (idx < lower) {
            return 1;
        }
        if (numParam - idx > 0) {
            // 有小数
            return numParam - idx;
        }
        return 0;


    });
    return arr;
};
import React from 'react';
import './index.less';
import {handleStar} from '@/utils/utils';

/**
 * 星级评分
 * @params {Number} number 星级得分
 * @params {Number} full 总分(共需要展示几个星星)默认五颗星
 * @params {String} baseColor 星星默认色值(没有得分时色值) 默认#E0E0E0
 * @params {String} fullColor 得分高亮的色值 默认#FF3333
 * @params {String} fontSize 控制星星宽度 默认20px
 * @params {String} lineHeight 星星高度 默认20px
 * @params {String} margin 星星间距 默认10px
 * @params {Number} step 默认按照0.5处理小数部分星星展示
 * @return {Null}
 */
export default function Star(props) {
    let {
        number = 0,
        fontSize = '20px',
        lineHeight = '20px',
        margin = '10px',
        full = 5,
        baseColor = '#E0E0E0',
        fullColor = '#FF3333',
        step
    } = props;
    if (step) {
        let remainder = number % 1;
        if (remainder && remainder > 0.5) {
            number = Math.floor(number) + 1;
        }
        else if (remainder && remainder < 0.5) {
            number = Math.floor(number) + 0.5;
        }
    }
    let defaultStar = {
        color: baseColor,
        lineHeight: lineHeight,
        fontSize: fontSize,
        marginRight: margin
    };
    let fullStarFun = value => {
        return {
            color: fullColor,
            width: value
        };
    };
    let clickItemStar = idx => {
        props.clickItemStar && props.clickItemStar(idx + 1);
    };
    return (
        <div className="innerstar-wrapper">
            {handleStar(number, full).map((item, idx) => (
                // eslint-disable-next-line react/no-array-index-key
                <span className="org_star" style={defaultStar} key={idx} onClick={() => clickItemStar(idx)}>
                    {item !== 0 && (
                        <span className="full-star" style={fullStarFun(item * 100 + '%')}>
                            &#xe62b;
                        </span>
                    )}
                    &#xe62b;
                </span>
            ))}
        </div>
    );
}
<div className='title-star'>
                        <Star
                            step={0.5}
                            number={item.star}
                            fullColor='#FFBF00'
                            fontSize='12px'
                            lineHeight='15px'
                            margin='2px'
                        />
                        {+item.star !== 0 && <span className='avg'>{item.star.toFixed(1)}</span>}
                    </div>

平滑滚动

/**
 * @param {*} element 滚动的元素 默认window
 * @param {*} scrollTo 要滚动到的距离
 * @return {*}
*/
const scrollSmooth = (scrollTo) => {
    if (isIOS) {
        const stepLength = 25;
        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        let distance = scrollTo - scrollTop;

        const step = () => {
            if (distance > 0) {
                scrollTop = scrollTop + stepLength > scrollTo ? scrollTo : scrollTop + stepLength;
            }
            if (distance < 0) {
                scrollTop = scrollTop - stepLength > scrollTo ? scrollTop - stepLength : scrollTo;
            }
            if (scrollTop === scrollTo) {
                window.scrollTo(0, scrollTop);
            }
            else {
                window.scrollTo(0, scrollTop);
                requestAnimationFrame(step);
            }
        };
        step();
    }
    else {
        // 安卓手百轻框架这样执行会卡顿,用原生方法实现
        window.scrollTo({
            top: scrollTo,
            behavior: 'smooth'
        });
    }

};
export {scrollSmooth};

axios请求

import axios from 'axios';
import qs from 'qs';

// 声明一个数组用于存储每个ajax请求的取消函数和ajax标识,只针对get请求取消
let pending = [];

let cancelToken = axios.CancelToken;
let removePending = config => {
    for (let item in pending) {
        // 当前请求在数组中存在时执行函数体
        if (pending[item].url === config.url) {
            // 执行取消操作
            pending[item].cancelFn();
            // 把这条记录从数组中移除
            pending.splice(item, 1);
        }
    }
};

const axiosInstance = axios.create();

axiosInstance.defaults.withCredentials = true;

// 添加请求拦截器
axiosInstance.interceptors.request.use(config => {
    if (config.abort) {
        removePending(config);
    }
    config.cancelToken = new cancelToken(token => {
        pending.push({
            cancelFn: token,
            url: config.url
        });
    });
    return config;
},
error => Promise.reject(error)
);

export const request = ({
    params,
    method = 'get',
    url,
    extParams = {},
    // 网络异常返回空对象还是错误信息
    errorReturnObject = false
}) => {
    if (method.toLowerCase() === 'post') {
        return axiosInstance.post(url, qs.stringify({
            ...params
        })).then(res => res.data).catch((e) => {
            return errorReturnObject ? {} : Promise.reject(e);
        });
    }

    extParams = Object.assign(
        {
            abort: 1
        },
        extParams
    );

    // 用promise包一下,不然重复请求取消时也会走到catch里
    return new Promise((resolve, reject) => {
        axiosInstance.get(url, {
            params: {
                ...params
            },
            ...extParams
        }).then(res => resolve(res.data)).catch((e) => {
            if (e && e.__CANCEL__) {
                console.warn('request 取消');
                return;
            }
            return errorReturnObject ? {} : reject(e);
        });
    });
};

export default request;

// 使用:post
/**
 * 返回一个对象字典排序后的字符串
 * @param {Object} data
 * @return {String} 字典排序后的字符串
*/
export const dictionaryOrder = (data) => {
    let str = '';
    const allkeys = Object.keys(data).sort();
    for (let i = 0, len = allkeys.length; i < len; i++) {
        str += `${allkeys[i]}=${data[allkeys[i]]}`;
    }
    return str;
};

export const getList = (options = {}) => {
    const params = {
        ts: +new Date(),
        ...options
    };
    params.sign = md5(dictionaryOrder(params) + token); // 是否需要md5加密
    return request({
        params,
        url: `${HOST}/xxx/list`,
        method: 'post'
    });
};
// get 
export const getList = (params = {}) => {
    const options = {
        ...params
    };
    const url = 'xxxx';
    return $get(url, options);
};

h5监听页面 visibilty 发生变化

export const onPageVisible = (callback) => {
    onVisibleEvent(() => {
        // 页面切换到前台
        if (callback) {
            callback();
        }
        else {
            window.location.reload();
        }
    }, () => {
        // 页面切换到后台
    });
};

数字单位转化(处理成万、亿)

export const formatNumData = num => {
    num = num || 0;
    let o = {
        num: num,
        unit: '',
    };
    // 1w 以下
    if (num < 10000) {
        return o.num;
    }
    // 1w以上 1亿以下
    if (num >= 10000 && num < 10000 * 10000) {
        let n = Math.floor((num / 10000) * 10) / 10;
        o.unit = '万';
        o.num = n;
        return o.num + o.unit;
    }
    // 1亿以上
    let n = Math.floor((num / (10000 * 10000)) * 10) / 10;
    o.unit = '亿';
    o.num = n;
    return o.num + o.unit;
};
// 处理过万展示
export const overFiveNumber = account => {
    return account > 1e4 ? (account / 1e4).toFixed(1) + '万' : account;
};

随机长字符串

export const randomString = length => {
    let chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let result = '';
    for (let i = length; i > 0; --i) {
        result += chars[Math.floor(Math.random() * chars.length)];
    }
    return result;
};

日期格式化

/**
 * 日期格式化
 * @function dateFormat
 * @param {Date} d - date 对象
 * @param {string} [pattern = 'yyyy-MM-dd'] - 字符串
 * @return {string} 处理后的字符串
 * @example
 *    var d = new Date();
 *  dateFormat(d," yyyy年M月d日\n yyyy-MM-dd\n MM-dd-yy\n yyyy-MM-dd hh:mm:ss")
 *  //2018年11月10日\n 2018-01-01\n 01-01-18\n 2018-11-12 12:01:02
 */
export const dateFormat = (d, pattern = 'yyyy-MM-dd') => {
    let y = d.getFullYear().toString();
    let o = {
        M: d.getMonth() + 1, // month
        d: d.getDate(), // day
        h: d.getHours(), // hour
        m: d.getMinutes(), // minute
        s: d.getSeconds(), // second
    };
    pattern = pattern.replace(/(y+)/gi, (a, b) => y.substr(4 - Math.min(4, b.length)));
    Object.keys(o).forEach(i => {
        pattern = pattern.replace(new RegExp('(' + i + '+)', 'g'), (a, b) => {
            return o[i] < 10 && b.length > 1 ? '0' + o[i] : o[i];
        });
    });
    return pattern;
};

运行环境的手机环境

const ua = navigator.userAgent.toLocaleLowerCase();
const browserList = {
    toutiao: /TTWebView\/([\d\.]+)/i,
    wechat: /MicroMessenger\/([\d\.]+)/i,
    ipadqq: /IPadQQ\/([\d\.]+)/i,
    mqq: /qq\/([\d\.]+)/i,
    qzone: /QZONEJSSDK\/([\d\.]+)/i,
    mqqbrowser: /mqqbrowser\/([\d\.]+)/i,
    qqbrowser: /[^m]QQBrowser\/([\d\.]+)/i,
    x5: /tbs\/(\d+)/i,
    uc: /UCBrowser\/([\d\.]+)/i,
    safari1: /Version\/(([\d\.]+))\sSafari\/[\d\.]+/i,
    safari2: /Safari\/([\d\.]+)/i,
    firefox: /Firefox\/([\d\.]+)/i,
    opera: /OPR\/([\d\.]+)/i,
    ie1: /MSIE\s([\d\.]+)/i,
    ie2: /(trident\/\d\.\d)/i,
    ie3: /(Edge)\/\d+\.\d+/i,
    weibo: /weibo__([\d\.]+)/i,
    qqnewsAd: /TADChid\/([\d\.]+)/i,
    qqnews: /qqnews\/([\d\.]+)/i,
    qqlive1: /QQLiveBrowser\/([\d\.]+)/i,
    qqlive2: /QQLiveHDBrowser\/([\d\.]+)/i,
    kuaibao: /qnreading\/([\d\.]+)/i,
    liebao: /LieBaoFast\/([\d\.]+)/i,
    douban: /com\.douban\.frodo\/([\d\.]+)/i,
    miuibrowser: /MiuiBrowser/i,
    baidulite: /lite baiduboxapp/i,
    baidupro: /pro baidubox/i,
    baiduinfo: /info baidubox/i,
    baidu: /baiduboxapp/i,
    baidukankan: /baiduboxvision/i,
    browser360: /360browser/i,
    oppobrowser: /OppoBrowser/i,
    chrome1: /CriOS\/([\d\.]+)/i,
    chrome2: /Chrome\/([\d\.]+)/i,
    qqdownloader: /qqdownloader\/([\d\.]+)/i,
    nintendo: /NintendoBrowser\/([\d\.]+)/i,
};
export const getBrwoserType = (ua = navigator.userAgent) => {
    for (let i in browserList) {
        if (ua.match(browserList[i])) {
            return i;
        }
    }
    return 'unknown';
};
export const isMobile = (ua = navigator.userAgent) => !!ua.match(/AppleWebKit.*Mobile.*/);

export const isPC = () => !window.navigator.userAgent.match(/Android|iPhone|SymbianOS|Windows Phone|iPad|Pod/);

获取手机品牌

export const getBrand = () => {
    let brand = '';
    /* eslint-disable */
    let phone = [/IPHONE/gi, /huawei/gi, /mi/gi, /vivo/gi, /OPPO/gi, /samsung/gi, /SONY/gi, /Nokia/gi, /HTC/gi, /ZTE/gi, /Lenovo/gi, /ZUK/gi];
    /* eslint-disable */
    if (phone[0].test(ua)) {
        brand = 'iPhone';
    } else if (phone[1].test(ua)) {
        brand = 'HUAWEI';
    } else if (phone[2].test(ua)) {
        brand = '小米';
    } else if (phone[3].test(ua)) {
        brand = 'vivo';
    } else if (phone[4].test(ua)) {
        brand = 'OPPO';
    } else if (phone[5].test(ua)) {
        brand = 'SAMSUNG';
    } else if (phone[6].test(ua)) {
        brand = 'SONY';
    } else if (phone[7].test(ua)) {
        brand = 'Nokia';
    } else if (phone[8].test(ua)) {
        brand = 'HTC';
    } else if (phone[9].test(ua)) {
        brand = 'ZTE';
    } else if (phone[10].test(ua) || phone[11].test(ua)) {
        brand = 'Lenovo';
    } else {
        brand = 'Android';
    }
    return brand;
};