常用工具方法总结

2020/05/15 JavaScript 本文共11178字,阅读全文约需40分钟 本文总阅读量

  常用工具方法总结。

千分位

export const comdify = (n) => {
  // 千分制
  n = '' + n;
  let isMinus = false;
  if (n.startsWith('-')) {
    isMinus = true;
    n = n.slice(1);
  }
  const re = /\d{1,3}(?=(\d{3})+$)/g;
  const n1 = n.replace(/^(\d+)((\.\d+)?)$/, function (s, s1, s2) {
    return s1.replace(re, '$&,') + s2;
  });
  return isMinus ? '-' + n1 : n1;
};

正则校验

// 常用正则验证
const checkStr = (str, type) => {
  switch (type) {
    case 'phone': //手机号码
      return /^1\d{10}$/.test(str);
    case 'tel': // 座机
      return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
    case 'card': // 身份证
      return /^\d{15}|\d{18}$/.test(str);
    case 'pwd': // 密码以字母开头,长度在6~18之间,只能包含字母、数字和下划线
      return /^[a-zA-Z]\w{5,17}$/.test(str);
    case 'postal': // 邮政编码
      return /[1-9]\d{5}(?!\d)/.test(str);
    case 'QQ': // QQ号 5-11位数字
      return /^[1-9]\d{4,10}$/.test(str);
    case 'email': // 邮箱
      return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
    case 'money': // 金额(小数点2位)
      return /^\d*(?:\.\d{0,2})?$/.test(str);
    case 'URL': // 网址
      return /(https?|ftp):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(
        str
      );
    case 'IP': // IP
      return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(
        str
      );
    case 'day': // 一个月的31天 01-09和1~31
      return /^((0?[1-9])|(([12])[0-9])|30|31)$/.test(str);
    case 'month': // 一年的12个月 01-09和1-12
      return /^(0?[1-9]|1[0-2])$/.test(str);
    case 'date': // 日期时间
      return (
        /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(
          str
        ) || /^(\d{4})\-(\d{2})\-(\d{2})$/.test(str)
      );
    case 'poInteger': // 整数 正整数
      return /^\d+$/.test(str);
    case 'integer': // 整数 正整数或负整数
      return /^-?\d+$/.test(str);
    case 'decimal': // 小数
      return /^(-?\d+)(\.\d+)?$/.test(str);
    case 'english': // 英文
      return /^[a-zA-Z]+$/.test(str);
    case 'chinese': // 中文
      return /^[\u4E00-\u9FA5]+$/.test(str);
    case 'cname': // 中文姓名 2-4位汉字
      return /^[\u4E00-\u9FA5]{2,4}$/.test(str);
    case 'lower': // 小写
      return /^[a-z]+$/.test(str);
    case 'upper': // 大写
      return /^[A-Z]+$/.test(str);
    case 'HTML': // HTML标记
      return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
    default:
      throw new Error('检验出错 in function checkStr');
  }
};

校验是否为中国大陆手机号

// 说明:现在已经出现了16开头的手机号,原正则`/^1[3,4,5,7,8][0-9]{9}$/`不再适用
function isTel(value) {
    return /^1[3,4,5,6,7,8,9][0-9]{9}$/.test(value.toString());
}

数据统计处理

// 去除字符串两边的空格 trim
String.prototype.trim = function() {
  return this.replace(/(^\s+)\|(\s+$)/g, '')
}
// 找出重复最多的字符
let str = 'asss23sjdssskssa7lsssdkjsssdss'
const repeatMost = (str) => {
const arr = str.split(/\s*/)              // 把字符串转换为数组
const str2 = arr.sort().join('')              // 首先进行排序,这样结果会把相同的字符放在一起,然后再转换为字符串
let value = ''
let index = 0
str2.replace(/(\w)\1*/g, function($0, $1) {         // 匹配字符
  if (index < $0.length) {
    index = $0.length              // index是出现次数
    value = $1                  // value是对应字符
  }
})
console.log(`最多的字符: ${value} ,重复的次数: ${index}`)
}
repeatMost(str)
// 数字格式化,1234567890 -> 1,234,567,890
const numFormat = str => str.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
// 手机号中间四位换*
const validateMobile = str => /^[1][0-9]{10}$/.test(str) && str.replace(/(\d{3})(\d{4})(\d{4})/, (rs, $1, $2, $3) => `${$1}****${$3}`)
// 取URL中query到一个对象中
function getUrlParam(str) {
  const result = {}
  const valid = /(https?|ftp):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.exec(str)
  if (!valid) return
  const [rs, $1, $2, $3] = valid
  $3.match(/[a-zA-Z_]+=[^=&?]*/g).forEach(val => val.replace(/^(\w+)=(\w*)$/, ($0, $1, $2) => {
        result[$1] = $2
      })
  )
  return result
}
getUrlParam('https://www.baidu.com?name=jawil&age=23&d=')         // {name: "jawil", age: "23", d: ""}
// 验证是否是合法URL
function validateURL(textval) {
  const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
  return urlregex.test(textval)
}
// HTML编码,对< / > " & \等字符转义,避免XSS攻击
function htmlEncode(str) {
  return str.replace(/[\<\>\"\'\&]/g, function(rs) {
    switch (rs) {
      case '<':
        return '&lt;'
      case '>':
        return '&gt;'
      case '&':
        return '&amp;'
      case ''':
        return '&apos;'
      case '"':
        return '&quot;'
    }
  })
}
// 批量写cookies
export const setCookieByBatch = (
  cookiesObj: {
    [key: string]: any;
  },
  days?: number
) => {
  let expires = 'Session';
  if (days) {
    const exp = new Date();
    exp.setTime(exp.getTime() + days * 86400000);
    expires = exp.toUTCString();
  }
  for (const key in cookiesObj) {
    // 同一个域内 cookie 是按名称来存储和检索的,不同名就不会出现被覆盖的情况
    // 使用escape编码,使用decodeURIComponent解码在中文情况下可能会报URI的错误
    document.cookie = `${key}=${encodeURIComponent(
      cookiesObj[key]
    )};expires=${expires}`;
  }
};

// 获取所有cookies
export const getAllCookie = () => {
  const cookies = document.cookie.split(/;\s*/);
  const jsonCookies = {};
  for (const item of cookies) {
    // 将每条数据以=号拆开
    const data = item.split('=');
    // 数组中的第一元素为属性名 第二一个为值【第二个为对象类型时,还需要继续decodeURIComponent,这里只做一层】
    jsonCookies[data[0]] = decodeURIComponent(data[1]);
  }
  return jsonCookies;
};

// 获取指定cookies
export const getCookie = (name: string) => {
  let arr;
  const reg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
  // eslint-disable-next-line no-cond-assign
  if ((arr = reg.exec(document.cookie))) {
    return decodeURIComponent(arr[2]);
  } else {
    return null;
  }
};

// 具体的删除cookie逻辑
const realDelCookie = (name: string, expires: any) => {
  const cval = getCookie(name);
  if (cval) {
    document.cookie = `${name}=${cval};expires=${expires.toUTCString()}`;
  }
};

/**
 * 删除cookie,支持批量
 * @param name
 */
export const delCookie = (name: string | string[]) => {
  const exp = new Date();
  exp.setTime(exp.getTime() - 1);
  if (Array.isArray(name)) {
    for (const item of name) {
      realDelCookie(item, exp);
    }
  } else {
    realDelCookie(name, exp);
  }
};

Storage 的 CRUD

const Store = {
  // 存储localstorage时候最好是封装一个自己的键值,在这个值里存储自己的内容对象,封装一个方法针对自己对象进行操作。避免冲突也会在开发中更方便。
  ns: 'letschat_web_storage',
  init: (ns = 'letschat_web_storage') => {
    const mydata = localStorage.getItem(ns);
    if (mydata) {
      return;
    }
    Store.ns = ns;
    localStorage.setItem(ns, '{"data":{}}');
  },
  // 检测浏览器是否支持localStorage
  check: () => {
    return Boolean(window.localStorage);
  },
  // 读取
  get: (key: string) => {
    let mydata = localStorage.getItem(Store.ns);
    if (!mydata) {
      return null;
    }
    mydata = JSON.parse(mydata);

    // @ts-expect-error
    return mydata.data[key];
  },
  // 存储
  set: (key: string, value: any) => {
    const { ns } = Store;
    let mydata = localStorage.getItem(Store.ns);
    if (!mydata) {
      Store.init();
      mydata = localStorage.getItem(ns);
    }
    mydata = JSON.parse(mydata as string);
    // @ts-expect-error
    mydata.data[key] = value;
    localStorage.setItem(ns, JSON.stringify(mydata));
  },
  remove: (key: string) => {
    // 读取
    let mydata = localStorage.getItem(Store.ns);
    if (!mydata) {
      return false;
    }

    mydata = JSON.parse(mydata);
    // @ts-expect-error
    mydata.data[key] = null;
    localStorage.setItem(Store.ns, JSON.stringify(mydata));
    return true;
  },
  clear: () => {
    // 清除对象
    localStorage.removeItem(Store.ns);
  },
  // 批量保存,data是一个字典
  setList: (data: { [key: string]: any }) => {
    for (const i in data) {
      Store.set(i, data[i]);
    }
  },
  // 批量删除,list是一个数组
  removeList: (list: string[]) => {
    for (let i = 0, len = list.length; i < len; i++) {
      Store.remove(list[i]);
    }
  },
};

删除 URL 中某个参数

// 删除url中某个参数
export const delUrlSearch = (name: string) => {
  let baseUrl = '';
  let url = location.href;
  if (url.includes('&')) {
    baseUrl = url.split('?')[0] + '?';
  } else {
    baseUrl = url.split('?')[0];
  }
  const query = url.split('?')[1];
  if (query?.includes(name)) {
    const obj = {};
    const arr: any = query.split('&');
    for (let i = 0; i < arr.length; i++) {
      const temp = arr[i].split('=');
      obj[temp[0]] = temp[1];
    }
    delete obj[name];
    url =
      baseUrl +
      JSON.stringify(obj)
        .replace(/[\"\{\}]/g, '')
        .replace(/\:/g, '=')
        .replace(/\,/g, '&');
  }
  window.history.pushState({}, '', url);
};

JS 活学活用正则表达式

简单的加密:字符串生成 base64

// 可用atob解密
export const Base64Handle = {
  // private property
  _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',

  // public method for encoding
  encode(input) {
    let output = '';
    let chr1;
    let chr2;
    let chr3;
    let enc1;
    let enc2;
    let enc3;
    let enc4;
    let i = 0;

    input = Base64Handle._utf8_encode(input);

    while (i < input.length) {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }

      output =
        output +
        this._keyStr.charAt(enc1) +
        this._keyStr.charAt(enc2) +
        this._keyStr.charAt(enc3) +
        this._keyStr.charAt(enc4);
    }

    return output;
  },

  // public method for decoding
  decode(input) {
    let output = '';
    let chr1;
    let chr2;
    let chr3;
    let enc1;
    let enc2;
    let enc3;
    let enc4;
    let i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');

    while (i < input.length) {
      enc1 = this._keyStr.indexOf(input.charAt(i++));
      enc2 = this._keyStr.indexOf(input.charAt(i++));
      enc3 = this._keyStr.indexOf(input.charAt(i++));
      enc4 = this._keyStr.indexOf(input.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output += String.fromCharCode(chr1);

      if (enc3 != 64) {
        output += String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output += String.fromCharCode(chr3);
      }
    }

    output = Base64Handle._utf8_decode(output);

    return output;
  },

  // private method for UTF-8 encoding
  _utf8_encode(string) {
    string = string.replace(/\r\n/g, '\n');
    let utftext = '';

    for (let n = 0; n < string.length; n++) {
      const c = string.charCodeAt(n);

      if (c < 128) {
        utftext += String.fromCharCode(c);
      } else if (c > 127 && c < 2048) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      } else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }
    }

    return utftext;
  },

  // private method for UTF-8 decoding
  _utf8_decode(utftext) {
    let string = '';
    let i = 0;
    let c = (c1 = c2 = 0);

    while (i < utftext.length) {
      c = utftext.charCodeAt(i);

      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      } else if (c > 191 && c < 224) {
        c2 = utftext.charCodeAt(i + 1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      } else {
        c2 = utftext.charCodeAt(i + 1);
        c3 = utftext.charCodeAt(i + 2);
        string += String.fromCharCode(
          ((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)
        );
        i += 3;
      }
    }

    return string;
  },
};

请求接口缓存

class ItemCache {
  constructor(data, timeout) {
    this.data = data;
    // 设定超时时间,设定为多少秒
    this.timeout = timeout;
    // 创建对象时候的时间,大约设定为数据获得的时间
    this.cacheTime = new Date().getTime();
  }
}

class ExpiresCache {
  // 定义静态数据map来作为缓存池
  static cacheMap = new Map();

  // 数据是否超时
  static isOverTime(name) {
    const data = ExpiresCache.cacheMap.get(name);

    // 没有数据 一定超时
    if (!data) return true;

    // 获取系统当前时间戳
    const currentTime = new Date().getTime();

    // 获取当前时间与存储时间的过去的秒数
    const overTime = (currentTime - data.cacheTime) / 1000;

    // 如果过去的秒数大于当前的超时时间,也返回null让其去服务端取数据
    if (Math.abs(overTime) > data.timeout) {
      // 此代码可以没有,不会出现问题,但是如果有此代码,再次进入该方法就可以减少判断。
      ExpiresCache.cacheMap.delete(name);
      return true;
    }

    // 不超时
    return false;
  }

  // 当前data在 cache 中是否超时
  static has(name) {
    return !ExpiresCache.isOverTime(name);
  }

  // 删除 cache 中的 data
  static delete(name) {
    return ExpiresCache.cacheMap.delete(name);
  }

  // 获取
  static get(name) {
    const isDataOverTime = ExpiresCache.isOverTime(name);
    //如果 数据超时,返回null,但是没有超时,返回数据,而不是 ItemCache 对象
    return isDataOverTime ? null : ExpiresCache.cacheMap.get(name).data;
  }

  static set(name, data, timeout) {
    // 设置 itemCache
    const itemCache = new ItemCache(data, timeout);
    //缓存
    ExpiresCache.cacheMap.set(name, itemCache);
  }
}

// 生成key值错误
const generateKeyError = new Error("Can't generate key from name and argument");

// 生成key值
function generateKey(name, params) {
  try {
    // 返回 字符串,函数名 + 函数参数
    return `${name}:${JSON.stringify(params)}`;
  } catch (_) {
    // 返回生成key错误
    return generateKeyError;
  }
}

// 使用时调用cachePostRequest这个方法,默认存储30分钟
export const cachePostRequest = async (
  path: string,
  params: { [key: string]: any },
  timeout = 1800
) => {
  // 生成key
  const key = generateKey(path, params);
  // 获得数据
  let data = ExpiresCache.get(key);
  if (!data) {
    data = await request(path, params);
    // 使用 30min 缓存,30min之后再次get就会 获取null 而从服务端继续请求
    const { status_code } = data;
    // 保证请求成功再缓存,status_code字段需要根据后端约定自行更换key值
    status_code === 200 && ExpiresCache.set(key, data, timeout);
  }
  return data;
};

前端常用工具方法

Search

    欢迎与我交流

    江南逰子

    Table of Contents