JavaScript 工具函数

105 阅读3分钟

格式化时间

function formatTime(date, format) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  format = format.replace('YYYY', year);
  format = format.replace('MM', month);
  format = format.replace('DD', day);
  format = format.replace('HH', hours);
  format = format.replace('mm', minutes);
  format = format.replace('ss', seconds);

  return format;
}

指定范围随机数

const rand = (min, max) => {
  return parseInt(Math.random()*(max - min + 1) + min, 10);
}
rand(1, 100);

随机字符串

const rand = (min, max) => {
    return parseInt(Math.random() * (max - min + 1) + min, 10);
};
const getRandStr = (len = 12) => {
    const base = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
    const max = base.length - 1;
    return Array(len).fill().map((_, idx) => base[rand(idx === 0 ? 10 : 0, max)]).join('');
};
getRandStr(100);

最简洁的模板引擎

function tpl(str, data){
  return str.replace(/\$\{(\w+)\}/g, function(_str,_substr){
    return data[_substr] || _str
  })
}
tpl('hello <b>${name}</b>, your age is <b>${age}</b>', {name: 'javascript', age: 20});

argbToRGB

function argbToRGB(color) {
    return '#'+ ('000000' + (color & 0xFFFFFF).toString(16)).slice(-6);
}
function decimal2hex(num) {
  return num.toString(16);
}

中文转unicode字符工具

function toUnicode(str, cssType) {
    var i = 0,
        l = str.length,
        result = [], //转换后的结果数组
        unicodePrefix, //unicode前缀 (example:\1234||\u1234)
        unicode16; //转换成16进制后的unicode
    //如果是css中使用格式为\1234之类
    unicodePrefix = (cssType && cssType.toLowerCase() === 'css') ? '\\' : '\\u';
    for (; i < l; i++) {
        //转为16进制的unicode, js及css里须转成16进制
        unicode16 = str.charCodeAt(i).toString(16);
        result.push( unicodePrefix + unicode16 );
    }
    return result.join('');
}
function toUnicode(theString) {
  var unicodeString = '';
  for (var i = 0; i < theString.length; i++) {
    var theUnicode = theString.charCodeAt(i).toString(16).toUpperCase();
    while (theUnicode.length < 4) {
      theUnicode = '0' + theUnicode;
    }
    theUnicode = '\\u' + theUnicode;
    unicodeString += theUnicode;
  }
  return unicodeString;
}



## xss
```js
function escapeChar(str) {
    if (str && typeof str === 'string') {
        return str
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/"/g, '&quot;')
            .replace(/>/g, '&gt;')
            .replace(/'/g, '&#39;')
            .replace(/ /g, '&nbsp;')
            .replace(/\n/g, '<br/>');
    }

    return str;
}

function reverseEscapeChar(str) {
    if (str && typeof str === 'string') {
        return str
            .replace(/&amp;/g, '&')
            .replace(/&lt;/g, '<')
            .replace(/&quot;/g, '"')
            .replace(/&gt;/g, '>')
            .replace(/&#39;/g, "'")
            .replace(/&#34;/g, '"')
            .replace(/&nbsp;/g, ' ')
            .replace(/<br\/>/g, '\n');
    }

    return str;
}

异步加载JS

const loadScript = (src) => new Promise((resolve) => {
  const script = document.createElement('script');
  if (script.readyState) {
    script.onreadystatechange  = function() {
      if (script.readyState == "loaded" || this.readyState == 'complete') {
        resolve();
      }
    }
  } else {
    script.onload = () => {
      resolve();
    }
  }
  script.src = src;
  document.head.appendChild(script);
});

debounce & throttle

function debounce(fn, delay) {
  let timer;
  return function (...args) {
    let context = this;
    clearTimeout(timer)
    timer = setTimeout(function () {
      fn.apply(context, args);
    }, delay);
  }
}
function throttle(fn, threshold) {
  var last
  var timer
  threshold || (threshold = 250)
  return function () {
    var context = this
    var args = arguments
    var now = +new Date()
    if (last && now < last + threshold) {
      clearTimeout(timer)
      timer = setTimeout(function () {
        last = now
        fn.apply(context, args)
      }, threshold)
    } else {
      last = now
      fn.apply(context, args)
    }
  }
}
function throttle(func, wait) {
    let lastTime
    return function(...rest) {
        if (!lastTime ||
          (new Date().getTime() - lastTime > wait)) {
            lastTime = +new Date()
            func.apply(this, rest)
        }
    }
}

获取URL参数

function getURLParams(key, url = window?.location?.href) {
    try {
        const r = (((url || '').split('?')[1] || '').split('#')[0] || '').match(new RegExp('(^|&)' + key + '=([^&]*)(&|$)', 'i'));

        if (r != null) {
            return decodeURIComponent(r[2]);
        }

        return '';
    } catch (error) {
        return '';
    }
}

获取DOM元素坐标

const getNodePosition = (o) => {
    let x = 0;
    let y = 0;
    while (o.offsetParent) {
        x += o.offsetLeft;
        y += o.offsetTop;
        o = o.offsetParent;
    }
    return {'x':x,'y':y};
}

判断是否支持H265

function isBrowserSupportH265() {
  const video = document.createElement('video');
  if (typeof video.canPlayType !== 'function') {
    return false;
  }
  const canPlay = video.canPlayType('video/mp4; codecs="hevc"');
  return ['maybe', 'probably'].includes(canPlay.toLowerCase());
}

判断元素是否在可见区域

function isElementInVisibleArea(elem, areaNode) {
  let viewport;
  if (areaNode) {
    viewport = areaNode.getBoundingClientRect();
  } else {
    viewport = {
      top: window.scrollY,
      left: window.scrollX,
      right: 0,
      bottom: 0
    };
    viewport.right = viewport.left + window.innerWidth;
    viewport.bottom = viewport.top + window.innerHeight;
  }

  const width = elem.offsetWidth;
  const height = elem.offsetHeight;
  const bodyRect = document.body.getBoundingClientRect();
  const elemRect = { ...elem.getBoundingClientRect() };
  elemRect.bottom = window.innerHeight - elemRect.top - elemRect.height;
  const bounds = {
    top: elemRect.top - bodyRect.top,
    right: 0,
    bottom: 0,
    left: elemRect.left - bodyRect.left
  };

  bounds.right = bounds.left + width;
  bounds.bottom = bounds.top + height;

  return !(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom);
}

IOS 修改页面标题

function updateDocumentTitle(title) {
  document.title = title;
  const iframe = document.createElement('iframe');
  const onload = () => {
    setTimeout(() => {
      iframe.removeEventListener('load', onload);
      document.body.removeChild(iframe);
    }, 0);
  };

  iframe.style.display = 'none';
  iframe.setAttribute('src', 'https://sta-op.douyucdn.cn/front-publish/fed-ci-static-bed-online/blank.110569e2.png');
  iframe.addEventListener('load', onload);
  document.body.appendChild(iframe);
}

获取元素before属性

function getElementBeforePropContent(selector) {
    var a = document.querySelector(selector);
    var b = getComputedStyle(a,':before').getPropertyValue('content');
    return b;
}

获取页面选中的文本内容

const SelectText = () => {
    try {
        const selecter = window.getSelection().toString();
        if (selecter != null && selecter.trim() != '') {
            return selecter;
        }
    } catch (err) {
        const selecter = document.selection.createRange();
        const s = selecter.text;
        if (s != null && s.trim() != '') {
            return s;
        }
    }
};

下载csv,中文不乱码

function createLink(str, filename='data.csv'){
    var a = document.createElement('a')
    // 解决中文乱码的问题
    str = '\uFEFF'+str
    var blob = new Blob([str], {type:'data:text/csv;charset=utf-8'});
  var url = URL.createObjectURL(blob);
  a.setAttribute('href', url);
  a.setAttribute('download', filename);
    a.click()
}
var str = 'a,b\n见义,你好'
createLink(str)

下载文件

function downloadBlob(blobData, filename) {
  const dataURL = URL.createObjectURL(blobData);
  const a = document.createElement('a');
  const fn = filename || `s_${+new Date()}.md`;
  a.href = dataURL;
  a.setAttribute('download', fn);
  a.innerHTML = 'downloading...';
  a.style.display = 'none';
  document.body.appendChild(a);
  setTimeout(() => {
    a.click();
    document.body.removeChild(a);
  }, 66);
}

下载文本

function downloadText(text, fn) {
  const dataURL = `data:text/plain;charset=utf-8,${encodeURIComponent(text)}`;
  const a = document.createElement('a');
  const filename = fn || `s_${+new Date()}.md`;
  a.href = dataURL;
  a.setAttribute('download', filename);
  a.innerHTML = 'downloading...';
  a.style.display = 'none';
  document.body.appendChild(a);
  setTimeout(() => {
    a.click();
    document.body.removeChild(a);
  }, 66);
}
downloadText('我是来自JavaScript下载的文件', 'test.js');

读文件

const reader = new FileReader();
reader.readAsText(e.target.files[0]);
// reader.readAsDataURL
// reader.readAsBinaryString
// reader.readAsArrayBuffer
reader.onload = () => {
  try {
    setList(JSON.parse(reader.result));
  } catch(err) {
    alert(err);
  }
};

base4转二进制文件

const dataURLtoFile = (dataurl, filename) => {
    const arr = dataurl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);

    while (n) {
        n -= 1;
        u8arr[n] = bstr.charCodeAt(n);
    }

    return new File([u8arr], filename, { type: mime });
};

获取系统剪切板的内容

navigator.clipboard.readText()
      .then(text => {
        console.log(text);
      })
      .catch(err => {
        console.error('Failed to read clipboard contents: ', err);
      });

复制文本到系统剪切板

export default (target, text) => {
  const copyText = (e) => {
    e.preventDefault();
    if (e.clipboardData) {
      e.clipboardData.setData('text/plain', text);
    } else if (window.clipboardData) {
      window.clipboardData.setData('Text', text);
    }
  };
  target.addEventListener('copy', copyText);
  document.execCommand('copy');
  target.removeEventListener('copy', copyText);
};

xml2json

function xml2json(xml, obj) {
    obj = obj || {};
    if (xml && xml.childNodes && xml.childNodes.length) {
        var childs = xml.childNodes,
            len = xml.childNodes.length;
        var item;
        if (len === 1 && (childs[0].nodeType === 3 || childs[0].nodeType === 4)) {
            if (isArray(obj)) {
                obj.push(childs[0].nodeValue);
            } else {
                obj = childs[0].nodeValue;
            }
        } else {
            for (var i = 0; i < len; i++) {
                item = childs[i];
                if (item.nodeType === 1) {
                    // 该节点已经存在,用数组装起来
                    if (obj.hasOwnProperty(item.nodeName) &&
                        !isArray(obj[item.nodeName])) {
                        obj[item.nodeName] = [obj[item.nodeName]];
                    }
                    if (isArray(obj[item.nodeName])) {
                        obj[item.nodeName].push(xml2json(item, {}));
                    } else {
                        obj[item.nodeName] = xml2json(item, {});
                    }
                }
            }
        }
    } else {
        obj = xml.nodeValue || '';
    }
    function isArray(a) {
        if (typeof a === 'object' && a.constructor === Array) return true;
        return false;
    }
    return obj
}

文本Base64

const txtBase64 = (txt) => window.btoa(txt);

检查对象类型

function typeof(obj) {
    const toString = Object.prototype.toString;
    const map = {
        '[object Boolean]':     'boolean',
        '[object Number]':      'number',
        '[object Undefined]':   'undefined',
        '[object Null]':        'null',
        '[object String]':      'string',
        '[object Object]':      'object',
        '[object Function]':    'function',
        '[object Array]':       'array',
        '[object Date]':        'date',
        '[object RegExp]':      'regExp',
        '[object Symbol]':      'symbol'
    };
    return map[toString.call(obj)];
}