# 1.延时函数,代替setTimeout,同步语法

// 睡眠若干毫秒, 与async/await配合使用
function sleep(ms) {
    return new Promise(resolve => {
        let timer = null
        timer = setTimeout(() => {
            resolve()
            clearTimeout(timer)
            timer = null
        }, ms)
    })
}
1
2
3
4
5
6
7
8
9
10
11

# 2、ascii16进制转换、hex编码解码

简洁方法,需要支持 TextEncoder

function encodeUtf8(str) {
    const encoder = new TextEncoder();

    return Array.from(encoder.encode(str))
        .map((item) => item.toString(16))
        .join("")
        .toUpperCase();
}
1
2
3
4
5
6
7
8
function decodeUtf8(str) {
    const decoder = new TextDecoder();

    let bytes = [];
    for (let j = 0; j < str.length; j += 2) {
        bytes.push(parseInt(str.slice(j, j + 2), 16));
    }

    return decoder.decode(new Uint8Array(bytes));
}
1
2
3
4
5
6
7
8
9
10

常规方法

function encodeUtf8(text) {
    let res = "";
    const code = encodeURIComponent(text);
    const bytes = [];
    for (let i = 0; i < code.length; i++) {
        const c = code.charAt(i);
        if (c === "%") {
            const hex = code.charAt(i + 1) + code.charAt(i + 2);
            const hexVal = parseInt(hex, 16);
            bytes.push(hexVal);
            i += 2;
        } else bytes.push(c.charCodeAt(0));
    }

    res = bytes
        .map((item) => item.toString(16))
        .join("")
        .toUpperCase();

    return res;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function decodeUtf8(str) {
    let bytes = [];
    for (let j = 0; j < str.length; j += 2) {
        bytes.push(parseInt(str.slice(j, j + 2), 16));
    }
    let encoded = "";
    for (let i = 0; i < bytes.length; i++) {
        encoded += "%" + bytes[i].toString(16);
    }
    return decodeURIComponent(encoded);
}
1
2
3
4
5
6
7
8
9
10
11

# 3、表情utf16处理

/**
   * 表情utf16
   * @param {String} str
   * @returns
*/
utf16toEntities(str) { 
    let patt = /[\ud800-\udbff][\udc00-\udfff]/g; // 检测utf16字符正则 
    str = str.replace(patt, function(char) { 
        let H, L, code; 
        if (char.length === 2) { 
        H = char.charCodeAt(0); // 取出高位 
        L = char.charCodeAt(1); // 取出低位 
        code = (H - 0xD800) * 0x400 + 0x10000 + L - 0xDC00; // 转换算法 
        return `&#${ code };`; 
        } else { 
        return char; 
        } 
    }); 
    return str; 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 /**
   * 解码utf16
   * @param {*} str
   * @returns
   */
uncodeUtf16(str) {
    console.log('str', str);
    const reg = /\&#.*?;/g;
    const result = str?.replace(reg, function(char) {
      let H, L, code;
      if (char.length == 9) {
        code = parseInt(char.match(/[0-9]+/g));
        H = Math.floor((code - 0x10000) / 0x400) + 0xd800;
        L = ((code - 0x10000) % 0x400) + 0xdc00;
        return unescape(`%u${ H.toString(16) }%u${ L.toString(16) }`);
      } else {
        return char;
      }
    });
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 4、字符串前置补位

/**
 * 前置补任意数字
 * @params num
 * @params targetLength 目标长度
 * @params hexadecimal 是否需要从10转16进制
 */
function padStartNum(num, targetLength, hexadecimal = false, str = '0') {
    let _str = ''
    if (hexadecimal) {
        _str = Number(num).toString(16)
    } else {
        _str = num.toString()
    }
    return _str.padStart(targetLength, str)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5、防抖和节流

/**
 * 防抖函数就是在一定时间内,再次触发函数就会清除定时器重新设置延迟时间执行,适用于非高频率操作。
 * @param  {Function} fn                [执行函数]
 * @param  {Number}   [interval=1000]       [间隔时间]
 * @param  {Boolean}  [immediate=false] [是否立即执行]
 * @return {[type]}                     [function]
 */
function debounce(fn, interval = 1000, immediate = false) {
    // 定时器
    let timer
    return function () {
        const self = this

        // 保存参数

        const args = arguments
        if (timer) clearTimeout(timer)
        // 是否立即执行
        if (immediate) {
            fn.apply(self, args)
            immediate = false
        }
        timer = setTimeout(() => {
            fn.apply(self, args)
        }, interval)
    }
}

/**
 * 节流函数就是只允许一个函数在一定时间内执行一次,适用于高频率事件。
 * @param  {Function} fn                [执行函数]
 * @param  {Number}   [interval=1000]       [间隔时间]
 * @return {[type]}                   [function]
 */
function throttle(fn, interval = 2000) {
    let timer

    let preTime = +new Date()
    return function () {
        const self = this

        const args = arguments

        const curTime = +new Date()
        if (timer) clearTimeout(timer)
        // 超过间隔时间执行,并记录当前时间是新的时间点
        if (curTime - preTime >= interval) {
            preTime = curTime
            fn.apply(self, arguments)
        } else {
            // 间隔时间内设置定时器,保证即使停止操作也至少执行一次
            timer = setTimeout(() => {
                fn.apply(self, args)
            }, interval)
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 6、bit位转换10进制,以及反解析以及设置对应bit位的值

/**
 * bit位转换10进制
 * @param {Array} list { value: 十进制值, bitStart: bit起始位, bitLen: bit的长度 }
 */
function bitConversion(list) {
    return list.reduce((pre, item) => {
        const { value, bitStart } = item;
        return pre + ((value << bitStart) >>> 0);
    }, 0);
}

/**
 * 获取对应bit区间的值
 * @param {Number} value 十进制数值 
 * @param {Number} bitStart bit起始位
 * @param {Number} bitLen bit的长度
 */
function getBitValue(value, bitStart, bitLen) {
    let t = '0b' + "1".repeat(bitLen);
    return (value >> bitStart) & t;
}

/**
 * 设置对应bit区间的值
 * @param {Number} originValue 原始十进制数值 
 * @param {Number} setValue 设置十进制数值 
 * @param {Number} bitStart bit起始位
 * @param {Number} bitLen bit的长度
 */
function setBitValue(originValue, setValue, {bitStart, bitLen}) {
    return (
        originValue -
        (getBitValue(originValue, bitStart, bitLen) << bitStart) +
        (setValue << bitStart)
    );
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# bitConversion example

// 【bit0、bit1~bit9(1~360)、bit10~bit17(0~100)、bit18~bit25(0~100】
const list = [
    { value: 1, bitStart: 0, bitLen: 1 },
    { value: 267, bitStart: 1, bitLen: 9 },
    { value: 67, bitStart: 10, bitLen: 8 },
    { value: 78, bitStart: 18, bitLen: 8 },
];

console.log(bitConversion(list)) // 20516375
1
2
3
4
5
6
7
8
9

# getBitValue example

list.forEach((item, index) => {
    console.log(getBitValue(bitConversion(list), item.bitStart, item.bitLen));
})

// 1
// 267
// 67
// 78
1
2
3
4
5
6
7
8

# setBitValue example

let _setBitValue = setBitValue(bitConversion(list), 11, list[2]);
list.forEach((item, index) => {
    console.log(getBitValue(_setBitValue, item.bitStart, item.bitLen));
});

// 1
// 267
// 11
// 78
1
2
3
4
5
6
7
8
9

# 7、hsv 转 rgb

/**
 * hsv 转 rgb
 * @param {Object} 颜色模式  H(hues)表示色相,S(saturation)表示饱和度,V)表示明度
*/
  hsv2rgb({ h, s, v }) {
    let i, f, p1, p2, p3;
    let r = 0,
      g = 0,
      b = 0;

    s = s / 100;
    v = v / 100;

    if (s < 0) s = 0;
    if (s > 1) s = 1;
    if (v < 0) v = 0;
    if (v > 1) v = 1;

    h %= 360;
    if (h < 0) h += 360;
    h /= 60;
    i = Math.floor(h);
    f = h - i;
    p1 = v * (1 - s);
    p2 = v * (1 - s * f);
    p3 = v * (1 - s * (1 - f));
    switch (i) {
      case 0:
        r = v;
        g = p3;
        b = p1;
        break;
      case 1:
        r = p2;
        g = v;
        b = p1;
        break;
      case 2:
        r = p1;
        g = v;
        b = p3;
        break;
      case 3:
        r = p1;
        g = p2;
        b = v;
        break;
      case 4:
        r = p3;
        g = p1;
        b = v;
        break;
      case 5:
        r = v;
        g = p1;
        b = p2;
        break;
    }

    return {
        r: Math.round(r * 255),
        g: Math.round(g * 255),
        b: Math.round(b * 255)
    };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# 8、rgb 转 hsv


// r,g,b范围为[0,255],转换成h范围为[1,360]
// s,v为百分比形式,范围是[0,100],可根据需求做相应调整
rgbToHsv(r, g, b) {
    r = (r || 0) / 255;
    g = (g || 0) / 255;
    b = (b || 0) / 255;
    let h, s, v;
    let min = Math.min(r, g, b);
    let max = (v = Math.max(r, g, b));
    let l = (min + max) / 2;
    let difference = max - min;

    if (max == min) {
      h = 0;
    } else {
      switch (max) {
        case r:
          h = (g - b) / difference + (g < b ? 6 : 0);
          break;
        case g:
          h = 2.0 + (b - r) / difference;
          break;
        case b:
          h = 4.0 + (r - g) / difference;
          break;
      }
      h = Math.round(h * 60);
    }

    if (h <= 0) {
      h = 1;
    }

    if (max == 0) {
      s = 0;
    } else {
      s = 1 - min / max;
    }
    s = Math.round(s * 100);
    v = Math.round(v * 100);

    if (h >= 360) {
      h = 359;
    }

    return { h, s, v };
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 9、前置补任意数字

 /**
 * 前置补任意数字
 * @params num
 * @params targetLength 目标长度
 * @params hexadecimal 是否需要从10转16进制
 * @params str 补充的字符
*/
padStartNum(num, targetLength, hexadecimal = false, str = "0") {
    let _str = "";
    if (hexadecimal) {
      _str = Number(num).toString(16);
    } else {
      _str = num.toString();
    }
    return _str.padStart(targetLength, str);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 10、图片路径拼接

/**
 * 图片路径拼接
 * @param {string} [path=''] 服务端返回的路径
 * @returns
 */
function parsingPath(path = '') {
    if (/(http|https):\/\/([\w.]+\/?)\S*/.test(path)) {
        return path
    }

    if (/^data*/.test(path)) {
        return path
    }
    return `${domain}/${path}`
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 11、获取文件类型

function getFileType(url) {
    let type = 'img'
    if (!url) {
        return type
    }
    var regex = /\.([0-9a-z]+)(?:[\?#]|$)/i
    var matches = url.match(regex)
    if (matches) {
        type = matches[1]
    }
    return type
}
1
2
3
4
5
6
7
8
9
10
11
12

# 12、获取URL参数

/**
 * 获取URL参数
 *
 * @param {*} name
 * @returns
 */
function getQueryString(name) {
    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
    var r = window.location.search.substr(1).match(reg)
    if (r != null) return r[2]
    if (r == null) {
        return getQueryVariable(name)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 13、将相对地址转绝地地址

/**
 * 将相对地址转绝地地址
 * @params { String } 相对地址
 * @returns { String } 绝对地址
 */
const getAbsoluteURL = url => {
    let link = document.createElement('a')
    let absoluteURL = ''

    link.href = url
    absoluteURL = link.href
    link = null

    return absoluteURL
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 14、睡眠若干毫秒

/**
 * 睡眠若干毫秒, 与async/await配合使用
 * @param {Number} ms 毫秒值
 */
function sleep(ms) {
    return new Promise(resolve => {
        let timer = setTimeout(() => {
            clearTimeout(timer)
            resolve()
        }, ms)
    })
}
1
2
3
4
5
6
7
8
9
10
11
12

# 15、格式化金钱,千分分隔

/**
 * 格式化金钱,千分分隔
 * @param {String | Number} num 数值
 * @param {String} sign 分割符号
 * @param {Number} addDecimal 添加小数位
 * @returns { String } 分割完成的字符串
 */
function formateMoneyCut(num, sign = ',', addDecimal = 0) {
    if (num) {
        if (!addDecimal) {
            return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, sign)
        } else {
            return num
                .toFixed(addDecimal)
                .toString()
                .replace(/\B(?=(\d{3})+(?!\d))/g, sign)
        }
    } else {
        let zero = 0
        return zero.toFixed(addDecimal)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 16、zip文件解析

import JSZip from 'jszip'
import JSZipUtils from 'jszip-utils'
/**
 * zip文件解析
 * @param {string} zipUrl zip地址
 * @returns {file} 文件
 */
function getZipFiles(zipUrl) {
    return new Promise((resolve, reject) => {
        JSZipUtils.getBinaryContent(zipUrl, async function (err, data) {
            let zipData = null
            if (err) {
                throw err; // or handle err
            }

            await JSZip.loadAsync(data).then(function (fileData) {
                zipData = fileData.files
            });

            resolve(zipData)
        });
    })
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 17、版本号比较

/**
 * Compares two software version numbers (e.g. "1.7.1" or "1.2b").
 *
 * This function was born in http://stackoverflow.com/a/6832721.
 *
 * @param {string} v1 The first version to be compared.
 * @param {string} v2 The second version to be compared.
 * @param {object} [options] Optional flags that affect comparison behavior:
 * lexicographical: (true/[false]) compares each part of the version strings lexicographically instead of naturally;
 *                  this allows suffixes such as "b" or "dev" but will cause "1.10" to be considered smaller than "1.2".
 * zeroExtend: ([true]/false) changes the result if one version string has less parts than the other. In
 *             this case the shorter string will be padded with "zero" parts instead of being considered smaller.
 *
 * @returns {number|NaN}
 * - 0 if the versions are equal
 * - a negative integer iff v1 < v2  负整数
 * - a positive integer iff v1 > v2  正整数
 * - NaN if either version string is in the wrong format
 */

function versionCompare(v1, v2, options) {
  var lexicographical = (options && options.lexicographical) || false,
    zeroExtend = (options && options.zeroExtend) || true,
    v1parts = (v1 || '0').split('.'),
    v2parts = (v2 || '0').split('.');

  function isValidPart(x) {
    return (lexicographical ? /^\d+[A-Za-zαß]*$/ : /^\d+[A-Za-zαß]?$/).test(x);
  }

  if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
    return NaN;
  }

  if (zeroExtend) {
    while (v1parts.length < v2parts.length) v1parts.push('0');
    while (v2parts.length < v1parts.length) v2parts.push('0');
  }

  if (!lexicographical) {
    v1parts = v1parts.map(function (x) {
      var match = (/[A-Za-zαß]/).exec(x);
      return Number(match ? x.replace(match[0], '.' + x.charCodeAt(match.index)) : x);
    });
    v2parts = v2parts.map(function (x) {
      var match = (/[A-Za-zαß]/).exec(x);
      return Number(match ? x.replace(match[0], '.' + x.charCodeAt(match.index)) : x);
    });
  }

  for (var i = 0; i < v1parts.length; ++i) {
    if (v2parts.length == i) {
      return 1;
    }

    if (v1parts[i] == v2parts[i]) {
      continue;
    }
    else if (v1parts[i] > v2parts[i]) {
      return 1;
    }
    else {
      return -1;
    }
  }

  if (v1parts.length != v2parts.length) {
    return -1;
  }

  return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

# 18、常用设备环境判断

export const browser = (() => {
    const ua = navigator.userAgent
    return {
        isAndroid: ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1, // android终端
        isIOS: !!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // iOS终端
        isPC: (() => { // PC终端
            const userAgentInfo = ua.toLowerCase()
            const Agents = new Array('android', 'iphone', 'symbianOS', 'windows phone', 'ipad', 'ipod')
            let flag = true
            for (let v = 0; v < Agents.length; v++) {
                if (userAgentInfo.indexOf(Agents[v]) > 0) {
                    flag = false
                    break
                }
            }
            return flag
        })(),
        isWeChat: /micromessenger/i.test(ua) || typeof WeixinJSBridge !== "undefined", // 微信环境
        isSafari: ua.indexOf('Safari') > -1 && ua.indexOf("Chrome") == -1, // safari浏览器
        isUC: ua.indexOf('UCBrowser') > -1 // UC浏览器
    }
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 19、vue指令,图片 onerror 替换默认图片

/**
 * 图片初始化默认图片,onerror替换默认图片
 * @param {IMG} initImg 初始默认图片
 * @param {IMG} errorImg 加载失败显示的图片
 */
Vue.directive('formatImage', function (el, binding) {
    const errorImg = (binding.value && binding.value.errorImg) || require('IMG/icon/default_avatar.png') // 加载失败的默认替换图
    const initImg = (binding.value && binding.value.initImg) || errorImg // 图片未加载的初始默认图
    const imgURL = el.getAttribute('src') // 实际图片地址
    el.src = initImg
    if (imgURL) {
        let image = new Image()
        image.src = imgURL
        image.onload = () => {
            el.src = imgURL
        }
    }
    el.onerror = () => {
        el.src = errorImg;
    }
}),

<img :src="rankList.list[0].icon" alt="" v-formatImage />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
lastUpdate: 11/23/2024, 2:02:04 PM