阅读 47

整理一下常用的JS工具函数,相信你会用得着

时间格式转换

使用方法:parseTime(1622536859864,"{y}-{m}-{d} {h}:{i}")
输出:"2021-06-01 16:40:59"
复制代码
/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0 || !time) {
    return null;
  }
  const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}";
  let date;
  if (typeof time === "object") {
    date = time;
  } else {
    if (typeof time === "string") {
      if (/^[0-9]+$/.test(time)) {
        // support "1548221490638"
        time = parseInt(time);
      } else if (/T/g.test(time)) {
        time = new Date(time);
      } else {
        time = time.replace(new RegExp(/-/gm), "/");
      }
    }

    if (typeof time === "number" && time.toString().length === 10) {
      time = time * 1000;
    }
    date = new Date(time);
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  };
  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key];
    // Note: getDay() returns 0 on Sunday
    if (key === "a") {
      return ["日", "一", "二", "三", "四", "五", "六"][value];
    }
    return value.toString().padStart(2, "0");
  });
  return time_str;
}
复制代码

过去距离当前时间格式转换

使用方法:formatTime(1622536859864);
输出:6分钟前
复制代码
/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (("" + time).length === 10) {
    time = parseInt(time) * 1000;
  } else {
    time = +time;
  }
  const d = new Date(time);
  const now = Date.now();

  const diff = (now - d) / 1000;

  if (diff < 30) {
    return "刚刚";
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + "分钟前";
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + "小时前";
  } else if (diff < 3600 * 24 * 2) {
    return "1天前";
  }
  if (option) {
    return parseTime(time, option);
  } else {
    return (
      d.getMonth() +
      1 +
      "月" +
      d.getDate() +
      "日" +
      d.getHours() +
      ":" +
      d
        .getMinutes()
        .toString()
        .padStart(2, "0")
    );
  }
}
复制代码

获取指定或者URL参数

使用方法:getQueryObject("https://www.baidu.com?channel=weixin");
输出:{channel: "weixin"}
复制代码
/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf("?") + 1);
  const obj = {};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}
复制代码

获取字符串字节长度

使用方法:byteLength("hello,沉默术士");
输出:18
复制代码
/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  let s = str.length;
  for (var i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s += 2;
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s;
}
复制代码

合并两个纯对象

/**
 *
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== "object") {
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice();
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === "object") {
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      target[property] = sourceProperty;
    }
  });
  return target;
}
复制代码

切换样式

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return;
  }
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += "" + className;
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length);
  }
  element.className = classString;
}
复制代码

函数防抖

export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result;

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp;

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

  return function(...args) {
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
}
复制代码

函数节流

/**
 * 函数节流
 * @param {Function} func
 * @param {Number} wait
 * @returns
 */
export function throttle(func, wait) {
  var timeout;
  return function() {
    var _this = this,
      args = arguments;
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null;
        func.apply(_this, args);
      }, wait);
    }
  };
}
复制代码

深克隆

/**
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone");
  }
  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys];
    }
  });
  return targetObj;
}
复制代码

数组去重

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr));
}
复制代码

唯一字符串

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + "";
  const randomNum = parseInt((1 + Math.random()) * 65536) + "";
  return (+(randomNum + timestamp)).toString(32);
}
复制代码

节点是否包含某个样式类名

export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
}
复制代码

节点添加样式类名

export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += " " + cls;
}
复制代码

移除样式类名

export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
    ele.className = ele.className.replace(reg, " ");
  }
}
复制代码

判断终端类型

export function getClient(){
      const ua = navigator.userAgent;
      let env = {
        ua: ua,
        isMobile: /android|iphone|ipod|ipad/i.test(ua),
        isIOS: /iphone|ipod|ipad|ios|mac os/i.test(ua),
        isAndroid: /android/i.test(ua),
        isWechat: /micromessenger/i.test(ua),
        isQQ: /qq\//i.test(ua),
        isWeibo: /weibo/i.test(ua),
        isDingTalk: /dingtalk/i.test(ua)
      };
      env.isBrowser = !(
        env.isWechat ||
        env.isQQ ||
        env.isWeibo ||
        env.isDingTalk
      );
      return env;
}
复制代码

判断是否是纯对象

  var _toString = Object.prototype.toString;
  function isPlainObject(obj) {
    return _toString.call(obj) === "[object Object]";
  }
复制代码

数字类型转换

  function toNumber(val) {
    var n = parseFloat(val);
    return isNaN(n) ? val : n;
  }

复制代码

判断两个数据类型是否是非严格相等

  function looseEqual(a, b) {
    if (a === b) {
      return true;
    }
    var isObjectA = isObject(a);
    var isObjectB = isObject(b);
    if (isObjectA && isObjectB) {
      try {
        var isArrayA = Array.isArray(a);
        var isArrayB = Array.isArray(b);
        if (isArrayA && isArrayB) {
          return (
            a.length === b.length &&
            a.every(function (e, i) {
              return looseEqual(e, b[i]);
            })
          );
        } else if (a instanceof Date && b instanceof Date) {
          return a.getTime() === b.getTime();
        } else if (!isArrayA && !isArrayB) {
          var keysA = Object.keys(a);
          var keysB = Object.keys(b);
          return (
            keysA.length === keysB.length &&
            keysA.every(function (key) {
              return looseEqual(a[key], b[key]);
            })
          );
        } else {
          /* istanbul ignore next */
          return false;
        }
      } catch (e) {
        /* istanbul ignore next */
        return false;
      }
    } else if (!isObjectA && !isObjectB) {
      return String(a) === String(b);
    } else {
      return false;
    }
  }
复制代码

只调用一次函数

  function once(fn) {
    var called = false;
    return function () {
      if (!called) {
        called = true;
        fn.apply(this, arguments);
      }
    };
  }
复制代码

数字格式化

/**
 * Number formatting
 * like 10000 => 1万
 * @param {number} num
 * @param {number} digits
 */
export function numberFormatter(num, digits = 2, round) {
  const si = [
    {
      value: 1e9,
      symbol: "亿"
    },
    {
      value: 1e4,
      symbol: "万"
    }
  ];
  for (let i = 0; i < si.length; i++) {
    if (num >= si[i].value) {
      if (round) {
        return (
          String(
            Math.floor((num / si[i].value) * Math.pow(10,digits)) / Math.pow(10,digits)
          ).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, "$1") + si[i].symbol
        );
      } else {
        return (
          (num / si[i].value)
            .toFixed(digits)
            .replace(/\.0+$|(\.[0-9]*[1-9])0+$/, "$1") + si[i].symbol
        );
      }
    }
  }
  return num.toFixed(digits);
}
复制代码

数字千位数格式化

/**
 * 10000 => "10,000"
 * @param {number} num
 */
export function toThousandFilter(num, digits = 2) {
  return (+num || 0)
    .toFixed(digits)
    .replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ","));
}
复制代码

字符串首字母大写

export function uppercaseFirst(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
}
复制代码
文章分类
前端
文章标签