工具函数

290 阅读12分钟

vue 项目中可以直接使用

常用工具类 untils.js 中

/*
 * 验证手机号是否合格
 * true--说明合格
 */
export function isPhone(phoneStr) {
  let myreg = /^[1][3,4,5,7,8,9][0-9]{9}$/;
  if (!myreg.test(phoneStr)) {
    return false;
  } else {
    return true;
  }
}

/*
 * 验证身份证号是否合格
 * true--说明合格
 */
export function isIdCard(idCardStr) {
  let idcardReg = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/;
  if (idcardReg.test(idCardStr)) {
    return true;
  } else {
    return false;
  }
}

/**
 * 验证车牌号是否合格
 * true--说明合格
 */
export function isVehicleNumber(vehicleNumber) {
  let xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
  let creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
  if (vehicleNumber.length == 7) {
    return creg.test(vehicleNumber);
  } else if (vehicleNumber.length == 8) {
    return xreg.test(vehicleNumber);
  } else {
    return false;
  }
}

/*
 * 验证字符串是否为空(也不能为纯空格)
 * true--说明为空, false--说明不为空
 */
export function isEmptyString(string) {
  if (
    string == undefined ||
    typeof string == 'undefined' ||
    !string ||
    string == null ||
    string == '' ||
    /^\s+$/gi.test(string)
  ) {
    return true;
  } else {
    return false;
  }
}

/*
 * 生日转为年龄(精确到月份)
 */
export function birsdayToAge(birsday) {
  let aDate = new Date();
  let thisYear = aDate.getFullYear();
  let bDate = new Date(birsday);
  let brith = bDate.getFullYear();
  let age = thisYear - brith;
  if (aDate.getMonth() == bDate.getMonth()) {
    if (aDate.getDate() < bDate.getDate()) {
      age = age - 1;
    }
  } else {
    if (aDate.getMonth() < bDate.getMonth()) {
      age = age - 1;
    }
  }
  return age;
}

/**
 * 判断数据类型
 * @param {any} val - 基本类型数据或者引用类型数据
 * @return {string} - 可能返回的结果有,均为小写字符串
 * number、boolean、string、null、undefined、array、object、function等
 */
export function getType(val){
  //判断数据是 null 和 undefined 的情况
  if (val == null) {
    return val + "";
  }
  return typeof(val) === "object" ?
      Object.prototype.toString.call(val).slice(8, -1).toLowerCase() :
      typeof(val);
}

/*
 * 验证是否为数字
 */
export function isNumber(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

/*
 * 是否为数组
 */
export function isArray(obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}

/*
 * 是否空数组
 */
export function isArrayEmpty(val) {
  if (val && val instanceof Array && val.length > 0) {
    return false;
  } else {
    return true;
  }
}

/*
 * 获取url参数字符串
 * 没有返回null
 */
export function getQueryString(name) {
  let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
  let r = window.location.search.substr(1).match(reg);
  if (r != null) {
    return unescape(r[2]);
  }
  return null;
}

/*
 * 递归深拷贝
 */
export function deepCopy(obj) {
  let result = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object' && obj[key] !== null) {
        result[key] = deepCopy(obj[key]);
      } else {
        result[key] = obj[key];
      }
    }
  }
  return result;
}

/**
 * 去除参数空数据(用于向后台传递参数的时候)
 * @param {Object} obj [参数对象]
 */
export function filterEmptyData(obj) {
  for (let prop in obj) {
    obj[prop] === '' ? delete obj[prop] : obj[prop];
  }
  return obj;
}

/**
 * @desc  函数防抖,用于将多次执行变为最后一次执行
 * @param {function} func - 需要使用函数防抖的被执行的函数。必传
 * @param {Number} wait - 多少毫秒之内触发,只执行第一次,默认1000ms。可以不传
 */
export function debounce(fn, delay) {
  delay = delay || 1000; //默认1s后执行
  let timer = null;
  return function () {
    let context = this;
    let arg = arguments;
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(context, arg);
    }, delay);
  };
}

/**
 * 节流函数, 用于将多次执行变为每隔一段时间执行
 * @param fn 事件触发的操作
 * @param delay 间隔多少毫秒需要触发一次事件
 */
export function throttle2(fn, delay) {
  let timer = null;
  return function () {
    let context = this;
    let args = arguments;
    if (!timer) {
      timer = setTimeout(function () {
        fn.apply(context, args);
        clearTimeout(timer);
      }, delay);
    }
  };
}

关于表单验证的

以下总结的为组件库中Form组件对应的自定义校验规则函数,本质上也用到了校验工具async-validator,更多的细节,可以去文档看,对于做后台系统的,涉及到大量的表单,表单验证必不可少。

验证手机号

function CheckPhone (rule, value, callback)  {
    let reg = /^1\d{10}$/g;
    if (!reg.test(value)) {
      callback(new Error('手机号格式不正确'));
    } else {
      callback();
    }
  }
复制代码

验证密码

function  CheckAdminPassword  (rule, value, callback) {
    const reg = /[\u4e00-\u9fa5]|\s+/gm;
    const len = value.length;
    if (value) {
      if (len < 8 || len > 14) {
        callback(new Error('密码必须由字母/数字及标点符号3种组成,且字母需大小写都包含,不得有空格、中文,长度8-14位'));
      }
      if (reg.test(value)) {
        callback(new Error('密码必须由字母/数字及标点符号3种组成,且字母需大小写都包含,不得有空格、中文,长度8-14位'));
      }
      if (!checkPwdCombination(value, 'admin')) {
        callback(new Error('密码须由字母/数字及标点符号3种组成,且字母需大小写都包含,不得有空格、中文,长度8-14位'));
      }
    }

    callback();
  }
复制代码

验证正整数(包含0)

function  CheckPositiveInteger (rule, value, callback){
    let reg = /^[1-9]\d*$/g;
    // console.log(value)
    if (!reg.test(value) && value !== '') {
      callback(new Error('请输入正整数'));
    } else {
      callback();
    }
  }
复制代码

验证邮箱

function  CheckEmail (rule, value, callback){
     let reg = /^[A-z0-9_]{3,12}@[A-z0-9]{2,12}(.com|.cn|.com.cn)$/g;
    if (!reg.test(value) && value !== '') {
      callback('邮箱格式不正确');
    } else {
      callback();
    }
  }
复制代码

验证价格

function CheckPrice (rule, value, callback)  {
    if (!value && value !== 0) {
      return callback(new Error('该项为必填项'));
    } else if (!parseFloat(value) && parseFloat(value) != 0) {
      return callback(new Error('请输入阿拉伯数字'));
    } else if (value < 0) {
      return callback(new Error('请输入正确的价格'));
    } else {
      callback();
    }
  }
复制代码

验证年龄

 function CheckAge (rule, value, callback)  {
    let reg = /\D/g;

    if (reg.test(value)) {
      callback(new Error('年龄只能为正整数'));
    } else if (parseInt(value) >= 120 || parseInt(value) < 0) {
      callback(new Error('年龄只能小于120'));
    } else {
      callback();
    }
  }
复制代码

验证IP地址

function CheckIp (rule, value, callback)  {
    let reg =
      /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]).(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]).(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]).(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
    if (!reg.test(value) && value !== '') {
      callback(new Error('输入正确IP地址'));
    } else {
      callback();
    }
  }

复制代码

验证域名网址

function CheckWebsite (rule, value, callback) {
    let reg = /(http|ftp|https)://[\w-_]+(.[\w-_]+)+([\w-.,@?^=%&:/~+#]*[\w-@?^=%&/~+#])?/;
    if (!reg.test(value) && value !== '') {
      callback(new Error('请输入正确的网址'));
    } else {
      callback();
    }
  }
复制代码

关于功能类的工具函数

主要用于数据转化,性能提升而用的

判断当前是电脑端还是移动端

const checkCurrentDeviceType = function () {
      let ua = navigator.userAgent.toLowerCase();
      let btypeInfo = (ua.match(/firefox|chrome|safari|opera/g) || 'other')[0];
      if ((ua.match(/msie|trident/g) || [])[0]) {
        btypeInfo = 'msie';
      }
      let pc = '';
      let prefix = '';
      let plat = '';
      //如果没有触摸事件 判定为PC
      let isTocuh = 'ontouchstart' in window || ua.indexOf('touch') !== -1 || ua.indexOf('mobile') !== -1;
      if (isTocuh) {
        if (ua.indexOf('ipad') !== -1) {
          pc = 'pad';
        } else if (ua.indexOf('mobile') !== -1) {
          pc = 'mobile';
        } else if (ua.indexOf('android') !== -1) {
          pc = 'androidPad';
        } else {
          pc = 'pc';
        }
      } else {
        pc = 'pc';
      }
      switch (btypeInfo) {
        case 'chrome':
        case 'safari':
        case 'mobile':
          prefix = 'webkit';
          break;
        case 'msie':
          prefix = 'ms';
          break;
        case 'firefox':
          prefix = 'Moz';
          break;
        case 'opera':
          prefix = 'O';
          break;
        default:
          prefix = 'webkit';
          break;
      }
      plat = ua.indexOf('android') > 0 ? 'android' : navigator.platform.toLowerCase();
      return {
        version: (ua.match(/[\s\S]+(?:rv|it|ra|ie)[/: ]([\d.]+)/) || [])[1], //版本
        plat: plat, //系统
        type: btypeInfo, //浏览器
        pc: pc,
        prefix: prefix, //前缀
        isMobile: pc == 'pc' ? false : true, //是否是移动端
      };
    };
复制代码

根据链接地址下载文件

    const dowloadFile = function (url) {
      let a = document.createElement('a');
      a.href = url;
      a.click();
    };
复制代码

判断起止时间一定要比结束时间小

const isValidTime = function (startTime, endTime)  {
      return new Date(endTime).getTime() > new Date(startTime).getTime();
    };
复制代码

树形结构数据转化(侧边栏或者权限管理)

 /**
     * @Description 组合接口返回的侧边栏路由为树形结构
     * @param { Array } data 需要处理的数据
     * @return { Array } 组合完成的树形结构
     **/
     
     /**
     转化规则如下:
          const data = [
      {
        parent: 0,
        label: '菜单1',
        id: 1,
      },
      {
        parent: 0,
        label: '菜单2',
        id: 2,
      },
      {
        parent: 0,
        label: '菜单3',
        id: 3,
      },
      {
        parent: 2,
        label: '菜单2-1',
        id: 4,
      },
      {
        parent: 3,
        label: '菜单3-1',
        id: 5,
      },
      {
        parent: 5,
        label: '菜单3-1-1',
        id: 6,
      },
    ];   ===>
    data = [
      {
        parent: 0,
        label: '菜单1',
        id: 1,
      },
      {
        parent: 0,
        label: '菜单2',
        id: 2,
        children:[
          {
            parent: 2,
            label: '菜单2-1',
            id: 4,
          },
        ]
      },
      {
        parent: 0,
        label: '菜单3',
        id: 3,
        children:[
          {
            parent: 3,
            label: '菜单3-1',
            id: 5,
            children:[
              {
                parent: 5,
                label: '菜单3-1-1',
                id: 6,
              },
            ]
          },
        ]
      },
    
    ]; 

     **/
const  getSideMenuListToTree = function (data) {
      data ? (data = data) : (data = []);
      let parent = data.filter(item => item.ParentId == 0); //一级菜单
      let childrens = data.filter(item => item.ParentId != 0); //子级菜单
      function formatToTree(parent, childrens) {
        parent.forEach(x => {
          childrens.forEach(v => {
            if (x.Id == v.ParentId) {
              x.children ? x.children.push(v) : (x.children = [v]);
              formatToTree(x.children, childrens);
            }
          });
        });
      }
      function solveTreeData(parent, list) {
        parent.forEach(item => {
          list.push({
            label: item.Title,
            path: item.Url,
            children: (item.children && item.children.length && solveTreeData(item.children, [])) || [],
          });
        });
        return list;
      }
      formatToTree(parent, childrens);
      let res = solveTreeData(parent, []);
      return res;
    };
    
    
复制代码

手机号脱敏显示

    /**
     *@Author:
     *@Description: 手机号脱敏处理
     * @param { String }   手机号 155xxxxx447
     * @return { String }   返回脱敏处理的手机号 155***447
     */
   const phoneDesensitizationTreatment = (phone)  {
      return phone.replace(/(\d{3})(\d{4})(\d{4})/, (str, $1, $2, $3) => {
        return $1 + '****' + $3;
      });
    };
复制代码

节流函数

    /**
     *@Author:
     *@Description: 节流函数
     * @param { Function }   fn 需要节流函数
     * @param { Number }   wait 间隔时间差
     * @param { Function }   callback  此回调函数用于获取函数返回值
     */
   const throw = function (fn, wait, callback)  {
      let initTime = 0;
      return function () {
        let nowTime = Date.now();
        if ((nowTime = initTime >= wait)) {
          let res = fn.apply(this, [...arguments]);
          if (typeof callback == 'function') callback(res);
          initTime = nowTime;
        }
      };
    };
复制代码

防抖函数

    /**
     *@Description: 防抖函数(简化版,项目需求够用了,也不是写啥子库,业务简单防抖就行,不需要花里胡哨的)
     * @param { Function }   fn 需要防抖的函数
     * @param { Number }   wait 间隔时间差
     * @param { Boolean }   immediate 是否开始立即执行
     * @param { Function }   callback  此回调函数用于获取函数返回值
     */
   const debounce = function (fn, wait, immediate = false, callback)  {
      let timer = null;
      let ivoke = false;
      return function () {
        if (timer) clearTimeout(timer);
        if (immediate && !ivoke) {
          let res = fn.apply(this, [...arguments]);
          if (typeof callback == 'function') callback(res);
          ivoke = true;
        } else {
          timer = setTimeout(() => {
            let res = fn.apply(this, [...arguments]);
            if (typeof callback == 'function') callback(res);
            ivoke = true;
          }, wait);
        }
      };
    };
复制代码

是生成浏览器设备标识

需要借助指纹库:Fingerprint2

//根据当前浏览器生成一个字符串标识当前主机 
 const getBrowerDeviceIdentificationId = async function () {
      return new Promise(async (resolve, reject) => {
        const fp = await Fingerprint2.load();
        const result = await fp.get();
        const visitorId = result.visitorId;
        resolve(visitorId);
      });
    };
复制代码

删除对象中的空值(根据需要可递归)

  // 删除对象中的空字段
   const deleteKey = function o(bj) {
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          const element = obj[key];
          if (element !== 0 && !element && typeof element !== 'boolean') {
            delete obj[key];
          }
        }
      }
      return obj;
    };
复制代码

时间转化

需要借助时间转化插件:moment.js

const transformDate = function (val, type)  {
      switch (type) {
        case 1:
          return moment(val).format('YYYY/MM/DD');
        case 2:
          return moment(val).format('YYYY-M-D');
        case 3:
          return moment(val).format('YYYY年M月');
        case 4:
          return moment(val).format('YYYY-MM-DD HH:mm');
        case 5:
          return moment(val).format('YYYY-MM-DD');
        case 6:
          return moment(val).format('YYYY年MM月DD日');
        case 7:
          return moment(val).fromNow(); //几天前/几年前/几秒前的格式
        case 8:
          return moment(val).format('YYYY/MM/DD HH:mm');
        case 9:
          return Math.floor((moment(val) - moment()) / 3600000); //时间相减剩余小时(主要用于设置过期时间)
      }
    };

日期补0 操作

/**
 * @description 日期的月或日补零操作
 * @param {String} value 需要补零的值
 */
function padZero(value) {
	return `00${value}`.slice(-2)
}

校验数据类型

export const typeOf = function(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
复制代码

示例:

typeOf('树哥')  // string
typeOf([])  // array
typeOf(new Date())  // date
typeOf(null) // null
typeOf(true) // boolean
typeOf(() => { }) // function
复制代码

防抖

export const debounce = (() => {
  let timer = null
  return (callback, wait = 800) => {
    timer&&clearTimeout(timer)
    timer = setTimeout(callback, wait)
  }
})()
复制代码

示例:

如 vue 中使用

methods: {
  loadList() {
    debounce(() => {
      console.log('加载数据')
    }, 500)
  }
}
复制代码

节流

export const throttle = (() => {
  let last = 0
  return (callback, wait = 800) => {
    let now = +new Date()
    if (now - last > wait) {
      callback()
      last = now
    }
  }
})()
复制代码

手机号脱敏

export const hideMobile = (mobile) => {
  return mobile.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2")
}
复制代码

开启全屏

export const launchFullscreen = (element) => {
  if (element.requestFullscreen) {
    element.requestFullscreen()
  } else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen()
  } else if (element.msRequestFullscreen) {
    element.msRequestFullscreen()
  } else if (element.webkitRequestFullscreen) {
    element.webkitRequestFullScreen()
  }
}
复制代码

关闭全屏

export const exitFullscreen = () => {
  if (document.exitFullscreen) {
    document.exitFullscreen()
  } else if (document.msExitFullscreen) {
    document.msExitFullscreen()
  } else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen()
  } else if (document.webkitExitFullscreen) {
    document.webkitExitFullscreen()
  }
}
复制代码

大小写转换

参数:

  • str 待转换的字符串
  • type 1-全大写 2-全小写 3-首字母大写
export const turnCase = (str, type) => {
  switch (type) {
    case 1:
      return str.toUpperCase()
    case 2:
      return str.toLowerCase()
    case 3:
      //return str[0].toUpperCase() + str.substr(1).toLowerCase() // substr 已不推荐使用
      return str[0].toUpperCase() + str.substring(1).toLowerCase()
    default:
      return str
  }
}
复制代码

示例:

turnCase('vue', 1) // VUE
turnCase('REACT', 2) // react
turnCase('vue', 3) // Vue
复制代码

判断手机是Andoird还是IOS

/** 
 * 1: ios
 * 2: android
 * 3: 其它
 */
export const getOSType=() => {
  let u = navigator.userAgent, app = navigator.appVersion;
  let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1;
  let isIOS = !!u.match(/(i[^;]+;( U;)? CPU.+Mac OS X/);
  if (isIOS) {
    return 1;
  }
  if (isAndroid) {
    return 2;
  }
  return 3;
}
复制代码

数组对象根据字段去重

参数:

  • arr 要去重的数组
  • key 根据去重的字段名
export const uniqueArrayObject = (arr = [], key = 'id') => {
  if (arr.length === 0) return
  let list = []
  const map = {}
  arr.forEach((item) => {
    if (!map[item[key]]) {
      map[item[key]] = item
    }
  })
  list = Object.values(map)

  return list
}
复制代码

示例:

const responseList = [
    { id: 1, name: '树哥' },
    { id: 2, name: '黄老爷' },
    { id: 3, name: '张麻子' },
    { id: 1, name: '黄老爷' },
    { id: 2, name: '张麻子' },
    { id: 3, name: '树哥' },
    { id: 1, name: '树哥' },
    { id: 2, name: '黄老爷' },
    { id: 3, name: '张麻子' },
]

uniqueArrayObject(responseList, 'id')
// [{ id: 1, name: '树哥' },{ id: 2, name: '黄老爷' },{ id: 3, name: '张麻子' }]
复制代码

滚动到页面顶部

export const scrollToTop = () => {
  const height = document.documentElement.scrollTop || document.body.scrollTop;
  if (height > 0) {
    window.requestAnimationFrame(scrollToTop);
    window.scrollTo(0, height - height / 8);
  }
}
复制代码

滚动到元素位置

export const smoothScroll = element =>{
    document.querySelector(element).scrollIntoView({
        behavior: 'smooth'
    });
};
复制代码

示例:

smoothScroll('#target'); // 平滑滚动到 ID 为 target 的元素
复制代码

uuid

export const uuid = () => {
  const temp_url = URL.createObjectURL(new Blob())
  const uuid = temp_url.toString()
  URL.revokeObjectURL(temp_url) //释放这个url
  return uuid.substring(uuid.lastIndexOf('/') + 1)
}
复制代码

示例:

uuid() // a640be34-689f-4b98-be77-e3972f9bffdd
复制代码

不过要吐槽一句的是,uuid一般应由后端来进行生成

金额格式化

参数:

  • {number} number:要格式化的数字
  • {number} decimals:保留几位小数
  • {string} dec_point:小数点符号
  • {string} thousands_sep:千分位符号
export const moneyFormat = (number, decimals, dec_point, thousands_sep) => {
  number = (number + '').replace(/[^0-9+-Ee.]/g, '')
  const n = !isFinite(+number) ? 0 : +number
  const prec = !isFinite(+decimals) ? 2 : Math.abs(decimals)
  const sep = typeof thousands_sep === 'undefined' ? ',' : thousands_sep
  const dec = typeof dec_point === 'undefined' ? '.' : dec_point
  let s = ''
  const toFixedFix = function(n, prec) {
    const k = Math.pow(10, prec)
    return '' + Math.ceil(n * k) / k
  }
  s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.')
  const re = /(-?\d+)(\d{3})/
  while (re.test(s[0])) {
    s[0] = s[0].replace(re, '$1' + sep + '$2')
  }

  if ((s[1] || '').length < prec) {
    s[1] = s[1] || ''
    s[1] += new Array(prec - s[1].length + 1).join('0')
  }
  return s.join(dec)
}
复制代码

示例:

moneyFormat(10000000) // 10,000,000.00
moneyFormat(10000000, 3, '.', '-') // 10-000-000.000
复制代码

存储操作

class MyCache {
  constructor(isLocal = true) {
    this.storage = isLocal ? localStorage : sessionStorage
  }

  setItem(key, value) {
    if (typeof (value) === 'object') value = JSON.stringify(value)
    this.storage.setItem(key, value)
  }

  getItem(key) {
    try {
      return JSON.parse(this.storage.getItem(key))
    } catch (err) {
      return this.storage.getItem(key)
    }
  }

  removeItem(key) {
    this.storage.removeItem(key)
  }

  clear() {
    this.storage.clear()
  }

  key(index) {
    return this.storage.key(index)
  }

  length() {
    return this.storage.length
  }
}

const localCache = new MyCache()
const sessionCache = new MyCache(false)

export { localCache, sessionCache }
复制代码

示例:

localCache.getItem('user')
sessionCache.setItem('name','树哥')
sessionCache.getItem('token')
localCache.clear()
复制代码

下载文件

参数:

  • api 接口
  • params 请求参数
  • fileName 文件名
const downloadFile = (api, params, fileName, type = 'get') => {
  axios({
    method: type,
    url: api,
    responseType: 'blob', 
    params: params
  }).then((res) => {
    let str = res.headers['content-disposition']
    if (!res || !str) {
      return
    }
    let suffix = ''
    // 截取文件名和文件类型
    if (str.lastIndexOf('.')) {
      fileName ? '' : fileName = decodeURI(str.substring(str.indexOf('=') + 1, str.lastIndexOf('.')))
      suffix = str.substring(str.lastIndexOf('.'), str.length)
    }
    //  如果支持微软的文件下载方式(ie10+浏览器)
    if (window.navigator.msSaveBlob) {
      try {
        const blobObject = new Blob([res.data]);
        window.navigator.msSaveBlob(blobObject, fileName + suffix);
      } catch (e) {
        console.log(e);
      }
    } else {
      //  其他浏览器
      let url = window.URL.createObjectURL(res.data)
      let link = document.createElement('a')
      link.style.display = 'none'
      link.href = url
      link.setAttribute('download', fileName + suffix)
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      window.URL.revokeObjectURL(link.href);
    }
  }).catch((err) => {
    console.log(err.message);
  })
}`
复制代码

使用:

downloadFile('/api/download', {id}, '文件名')
复制代码

时间操作

关于时间操作,没必要自己再写一大串代码了,强烈推荐使用 day.js

Day.js 是一个仅 2kb 大小的轻量级 JavaScript 时间日期处理库,下载、解析和执行的JavaScript更少,为代码留下更多的时间。

深拷贝

export const clone = parent => {
  // 判断类型
  const isType = (obj, type) => {
    if (typeof obj !== "object") return false;
    const typeString = Object.prototype.toString.call(obj);
    let flag;
    switch (type) {
      case "Array":
        flag = typeString === "[object Array]";
        break;
      case "Date":
        flag = typeString === "[object Date]";
        break;
      case "RegExp":
        flag = typeString === "[object RegExp]";
        break;
      default:
        flag = false;
    }
    return flag;
  };

  // 处理正则
  const getRegExp = re => {
    var flags = "";
    if (re.global) flags += "g";
    if (re.ignoreCase) flags += "i";
    if (re.multiline) flags += "m";
    return flags;
  };
  // 维护两个储存循环引用的数组
  const parents = [];
  const children = [];

  const _clone = parent => {
    if (parent === null) return null;
    if (typeof parent !== "object") return parent;

    let child, proto;

    if (isType(parent, "Array")) {
      // 对数组做特殊处理
      child = [];
    } else if (isType(parent, "RegExp")) {
      // 对正则对象做特殊处理
      child = new RegExp(parent.source, getRegExp(parent));
      if (parent.lastIndex) child.lastIndex = parent.lastIndex;
    } else if (isType(parent, "Date")) {
      // 对Date对象做特殊处理
      child = new Date(parent.getTime());
    } else {
      // 处理对象原型
      proto = Object.getPrototypeOf(parent);
      // 利用Object.create切断原型链
      child = Object.create(proto);
    }

    // 处理循环引用
    const index = parents.indexOf(parent);

    if (index != -1) {
      // 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象
      return children[index];
    }
    parents.push(parent);
    children.push(child);

    for (let i in parent) {
      // 递归
      child[i] = _clone(parent[i]);
    }

    return child;
  };
  return _clone(parent);
};

复制代码

此方法存在一定局限性:一些特殊情况没有处理: 例如Buffer对象、Promise、Set、Map。

如果确实想要完备的深拷贝,推荐使用 lodash 中的 cloneDeep 方法。

模糊搜索

参数:

  • list 原数组
  • keyWord 查询的关键词
  • attribute 数组需要检索属性
export const fuzzyQuery = (list, keyWord, attribute = 'name') => {
  const reg = new RegExp(keyWord)
  const arr = []
  for (let i = 0; i < list.length; i++) {
    if (reg.test(list[i][attribute])) {
      arr.push(list[i])
    }
  }
  return arr
}
复制代码

示例:

const list = [
  { id: 1, name: '树哥' },
  { id: 2, name: '黄老爷' },
  { id: 3, name: '张麻子' },
  { id: 4, name: '汤师爷' },
  { id: 5, name: '胡万' },
  { id: 6, name: '花姐' },
  { id: 7, name: '小梅' }
]
fuzzyQuery(list, '树', 'name') // [{id: 1, name: '树哥'}]
复制代码

遍历树节点

export const foreachTree = (data, callback, childrenName = 'children') => {
  for (let i = 0; i < data.length; i++) {
    callback(data[i])
    if (data[i][childrenName] && data[i][childrenName].length > 0) {
      foreachTree(data[i][childrenName], callback, childrenName)
    }
  }
}
复制代码

示例:

假设我们要从树状结构数据中查找 id 为 9 的节点

const treeData = [{
  id: 1,
  label: '一级 1',
  children: [{
    id: 4,
    label: '二级 1-1',
    children: [{
      id: 9,
      label: '三级 1-1-1'
    }, {
      id: 10,
      label: '三级 1-1-2'
    }]
  }]
 }, {
  id: 2,
  label: '一级 2',
  children: [{
    id: 5,
    label: '二级 2-1'
  }, {
    id: 6,
    label: '二级 2-2'
  }]
  }, {
    id: 3,
    label: '一级 3',
    children: [{
      id: 7,
      label: '二级 3-1'
    }, {
      id: 8,
      label: '二级 3-2'
    }]
}],

let result
foreachTree(data, (item) => {
  if (item.id === 9) {
    result = item
  }
})
console.log('result', result)  // {id: 9,label: "三级 1-1-1"}   
复制代码


以下这些是项目中用到的,封装的方法,如果有问题虚心求教。

正则手机号验证

function isMobile (mobile) {  
  return /^1[3-9]\d{9}$/.test(mobile)
}
复制代码

截取url参数

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
}
getQueryObject('https//www.baidu.com?id=1111&type=edit')
复制代码

格式化时间(方法1)

function parseTime(time, cFormat) {
  if (arguments.length === 0) {
    return null
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
      time = parseInt(time)
    }
    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(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}
// 使用
parseTime(new Date(),'{y}-{m}-{d} {h}:{i}:{s}')
复制代码

格式化时间(方法2)

/**
 * 格式化时间
 */
function NewTime(time) {
  if (!time) time = new Date()
  const t = new Date(time) // 你已知的时间
  t.setTime(t.setMinutes(t.getMinutes())) // 设置新时间比旧时间多一分钟
  const Y = t.getFullYear()
  let M = t.getMonth() + 1
  let D = t.getDate()
  let HH = t.getHours()
  let MM = t.getMinutes()
  let SS = t.getSeconds()
  if (M < 10) M = '0' + M
  if (D < 10) D = '0' + D
  if (HH < 10) HH = '0' + HH
  if (MM < 10) MM = '0' + MM
  if (SS < 10) SS = '0' + SS
  // let date_value = Y + '-' + M + '-' + D + ' ' + HH + ':' + MM + ':' + SS;
  const date_value = Y + '-' + M + '-' + D + ' ' + HH + ':' + MM + ':' + SS
  return date_value
}
复制代码

存储、获取、删除 sessionStorage

function __setItem(name, content) {
  if (!name) return;
  if (typeof content !== 'string') {
    content = JSON.stringify(content);
  }
  window.sessionStorage.setItem(name, content);
};
​
function __getItem(name) {
  if (!name) return;
  return window.sessionStorage.getItem(name);
};
​
​
function __removeItem(name) {
  if (!name) return;
  window.sessionStorage.removeItem(name);
};
复制代码

检测手机号

function _isMobile(mobile) {
  var reg = /^[1][3,4,5,7,8][0-9]{9}$/;
  if (reg.test(mobile)) return true;
  else return false;
};
复制代码

将base64转换为文件

function dataURLtoFile(dataurl, filename) {
  var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
}
复制代码

替换电话号码中间四位

function replacePhone(num) {
  let mphone = num;
  if (_isMobile(num)) {
    mphone = num.substr(0, 3) + '****' + num.substr(7);
  }
  return mphone;
};
复制代码

去除内容中的空格

function deblank(str) {
  str = str.replace(/\s*/g, '');
  return str;
};
复制代码

数字内添加逗号

如何将浮点数点左边的数每三位添加一个逗号,如12000000.11转化为『12,000,000.11』?
function commafy(num){
    return num && num
        .toString()
        .replace(/(\d)(?=(\d{3})+.)/g, function($1, $2){
            return $2 + ',';
        });
  }
​

电话号码格式344替换

function phoneSeparated(num) {
  let mphone = num;
  if (_isMobile(num)) {
    mphone =
      num.substring(0, 3) +
      ' ' +
      num.substring(3, 7) +
      ' ' +
      num.substring(7, 11);
  }
  return mphone;
};
复制代码

银行卡格式4444替换

function cardSeparated(num) {
  let index = num ? num.length / 4 : 0;
  let result = '';
  for (let i = 0; i < index; i++) {
    result += num.substring(i * 4, (i + 1) * 4) + ' ';
  }
  return result;
};
复制代码

身份证格式生日替换

function identityCardSeparated(num) {
  if (num.length === 18) {
    var str = num.substr(0, 6) + '********' + num.substr(14);
    return str;
  } else {
    return num;
  }
};
复制代码

护照号替换

function passportSeparated(num) {
  if (num.length > 4) {
    var str = num.substr(0, num.length - 4) + '****';
    return str;
  } else {
    return num;
  }
};
复制代码

卡号每隔四位加短线

function cardNoFormat(cardNo) {
  if (typeof cardNo == 'number') {
    cardNo = String(cardNo).replace(/\D/g, '').replace(/....(?!$)/g, '$&-');
  } else {
    cardNo = cardNo.replace(/\D/g, '').replace(/....(?!$)/g, '$&-');
  }
  return cardNo;
};
console.log(cardNoFormat('124141251512'))
console.log(cardNoFormat(1233124124124124))
复制代码

简单的深拷贝 deepClone

function deepClone(data) {
  if (!data && typeof data !== 'object') {
    throw new Error('error arguments', 'deepClone')
  }
  const obj = data.constructor === Array ? [] : {}
  Object.keys(data).forEach(keys => {
    if (data[keys] && typeof data[keys] === 'object') {
      obj[keys] = deepClone(data[keys])
    } else {
      obj[keys] = data[keys]
    }
  })
  return obj
}
var arr = [1,2,3,4,5,6];
console.log(deepClone(arr))
​
arr = [...arr, ...[7,8,9]]
console.log(arr, 'arr')
复制代码

每隔四位加空格

function fourSpace(num) {
  var value = num
    .replace(/\D/g, '')
    .replace(/....(?!$)/g, '$& ');
  return value;
};
fourSpace('13122223333')
复制代码

身份证校验

function IdentityCodeValid(code) {
  let city = {
    11: '北京',
    12: '天津',
    13: '河北',
    14: '山西',
    15: '内蒙古',
    21: '辽宁',
    22: '吉林',
    23: '黑龙江',
    31: '上海',
    32: '江苏',
    33: '浙江',
    34: '安徽',
    35: '福建',
    36: '江西',
    37: '山东',
    41: '河南',
    42: '湖北 ',
    43: '湖南',
    44: '广东',
    45: '广西',
    46: '海南',
    50: '重庆',
    51: '四川',
    52: '贵州',
    53: '云南',
    54: '西藏 ',
    61: '陕西',
    62: '甘肃',
    63: '青海',
    64: '宁夏',
    65: '新疆',
    71: '台湾',
    81: '香港',
    82: '澳门',
    91: '国外'
  };
  let tip = '';
  let pass = true;
  if (!code || !/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(code)) {
    tip = '身份证号格式错误';
    pass = false;
  } else if (!city[code.substr(0, 2)]) {
    tip = '地址编码错误';
    pass = false;
  }
  if (!pass) message.error(tip);
  return pass;
};
复制代码

HmacSHA256加密

function encryptHmacSHA256(value) {
  const userInfo = getUserInfo();
  let key = '';
  if (userInfo.data) {
    key = userInfo.data.publicKey;
  }
  let ciphertext = CryptoJS.HmacSHA256(value, key);
  let hashInBase64 = CryptoJS.enc.Base64.stringify(ciphertext);
  return hashInBase64;
};
复制代码

对象中的null转为空字符串

function _replaceNull(obj) {
  if (typeof obj === 'object') {
    Object.keys(obj).forEach(element => {
      let value = obj[element];
      if (value === null || value === undefined) {
        // obj[element] = '';
        delete obj[element];
      } else if (typeof value === 'object') {
        _replaceNull(value);
      }
    });
  }
  return obj;
};
复制代码

文件导出

function _checkoutFile(fileName, response) {
  console.log('response');
  console.log(response);
  let blob = new Blob([response], { type: 'application/vnd.ms-excel' });
  let objectUrl = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.setAttribute('href', objectUrl);
  a.setAttribute('download', fileName);
  a.click();
  URL.revokeObjectURL(objectUrl);
};
复制代码

url文件导出

function _urlExportFile(url) {
  const a = document.createElement('a');
  a.setAttribute('href', url);
  a.click();
};
复制代码

url校验

function validateURL(url, list) {
  let i = 0;
  if (list) {
    list.forEach(el => {
      if (url === el) {
        i = 1;
      }
    });
  }
  if (i !== 0) return false;
  if (i === 0) return true;
};
复制代码

页面可视高度、 页面可视宽度

function clientHeight() {
  let clientHeight = document.getElementById('root').clientHeight;
  let offsetHeight = document.getElementById('root').offsetHeight;
  return clientHeight || offsetHeight;
};
​
function clientWidth() {
  let clientWidth = document.getElementById('root').clientWidth;
  let offsetWidth = document.getElementById('root').offsetWidth;
  return clientWidth || offsetWidth;
};
复制代码

格式化金额

function formatMoney(val) {
  var valStr = String(Number(val).toFixed());
  var prefix_val, suffix_val, prefix_result, prefix_arr = null;
  var j, t, i = 0;
  let negativeFlag = false; //负数
  if (isNaN(Number(valStr))) {
    return val
  }
  if(Number(valStr) < 0){
    negativeFlag = true;
    valStr = String(Math.abs(valStr))
  }
  if (valStr.length < 3) {
    valStr = prefix(valStr, 3)
  }
  prefix_val = valStr.slice(0, -2)
  suffix_val = valStr.slice(-2)
  prefix_result = []
  prefix_arr = prefix_val.split("")
  j = 0
  t = 3
  for (i = prefix_arr.length - 1; i >= 0; i--) {
    j++
    if (j === t || i === 0) {
      prefix_result.unshift(prefix_arr.splice(i).join(""))
      j = 0
    }
  }
  if(negativeFlag){
    return '-' + prefix_result.join(",") + "." + suffix_val
  }else{
    return prefix_result.join(",") + "." + suffix_val
  }
}
formatMoney(1111111)

字符串换行办法

先大概说下思路:

  • 首先将字符串转换成数组 str.split('')
  • 在设定的位置添加换行符
  • 最后将数据在转换成字符串

代码如下:

splitByLine(str, len=10){
    let strLen = str.length,
        num = 0,
        multiple = Math.floor(strLen / len),
        arrStr = str.split(''),
        space = strLen % len > 0 ? multiple + 1 : multiple
    for (let i = 1; i <= space; i++) {
      arrStr.splice((len * i + num), 0, '\n')
      num ++
    }
    return arrStr.join('')
  }

我们来测试一下:

let str = '我是一个粉刷匠粉刷本领强把我们的新房子刷的很漂亮哈哈'
splitByLine(str) // 第二个参数不传。默认每10个字处开始换行

打印结果:

img

生成随机颜色

你的网站是否需要生成随机颜色?下面一行代码就可以实现。

const generateRandomHexColor = () => `#${Math.floor(Math.random() * 0xffffff).toString(16)}`

console.log(generateRandomHexColor())

数组重排序

对数组的元素进行重新排序是一项非常重要的技巧,但是原生 Array 中并没有这项功能。

const shuffle = (arr) => arr.sort(() => Math.random() - 0.5)

const arr = [1, 2, 3, 4, 5]
console.log(shuffle(arr))

复制到剪切板

复制到剪切板是一项非常实用且能够提高用户便利性的功能。

const copyToClipboard = (text) => navigator.clipboard && navigator.clipboard.writeText && navigator.clipboard.writeText(text)

copyToClipboard("Hello World!")

检测暗色主题

暗色主题日益普及,很多用的都会在设备中启用案模式,我们将应用程序切换到暗色主题可以提高用户体验度。

const isDarkMode = () => window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;

console.log(isDarkMode())
复制代码

滚动到顶部

将元素滚动到顶部最简单的方法是使用 scrollIntoView。设置 block 为 start 可以滚动到顶部;设置 behavior 为 smooth 可以开启平滑滚动。

const scrollToTop = (element) => 
  element.scrollIntoView({ behavior: "smooth", block: "start" });

滚动到底部

与滚动到顶部一样,滚动到底部只需要设置 block 为 end 即可。

const scrollToBottom = (element) => 
  element.scrollIntoView({ behavior: "smooth", block: "end" });

检测元素是否在屏幕中

检查元素是否在窗口中最好的方法是使用 IntersectionObserver。

const callback = (entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      // `entry.target` is the dom element
      console.log(`${entry.target.id} is visible`);
    }
  });
};

const options = {
  threshold: 1.0,
};
const observer = new IntersectionObserver(callback, options);
const btn = document.getElementById("btn");
const bottomBtn = document.getElementById("bottom-btn");
observer.observe(btn);
observer.observe(bottomBtn);

检测设备

使用 navigator.userAgent 来检测网站运行在哪种平台设备上。

const detectDeviceType = () =>
  /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
    navigator.userAgent
  ) ? "Mobile" : "Desktop";

console.log(detectDeviceType());
复制代码

隐藏元素

我们可以将元素的 style.visibility 设置为 hidden,隐藏元素的可见性,但元素的空间仍然会被占用。如果设置元素的 style.display 为 none,会将元素从渲染流中删除。

const hideElement = (el, removeFromFlow = false) => {
  removeFromFlow ? (el.style.display = 'none')
  : (el.style.visibility = 'hidden')
}

从 URL 中获取参数

JavaScript 中有一个 URL 对象,通过它可以非常方便的获取 URL 中的参数。

const getParamByUrl = (key) => {
  const url = new URL(location.href)
  return url.searchParams.get(key)
}

深拷贝对象

深拷贝对象非常简单,先将对象转换为字符串,再转换成对象即可。

const deepCopy = obj => JSON.parse(JSON.stringify(obj))

除了利用 JSON 的 API,还有更新的深拷贝对象的 structuredClone API,但并不是在所有的浏览器中都支持。

structuredClone(obj)

等待函数

JavaScript 提供了 setTimeout 函数,但是它并不返回 Promise 对象,所以我们没办法使用 async 作用在这个函数上,但是我们可以封装等待函数。

const wait = (ms) => new Promise((resolve)=> setTimeout(resolve, ms))

const asyncFn = async () => {
  await wait(1000)
  console.log('等待异步函数执行结束')
}

asyncFn()

01-随机获取布尔值

此函数将使用Math.random()方法返回布尔值(真或假)。 Math.random创建一个介于0和1之间的随机数,然后我们检查它是否大于或小于0.5。 这意味着有50/50的机会会得到对或错。

const getRandomBoolean = () => Math.random() >= 0.5;

console.log(getRandomBoolean());
// a 50/50 chance of returning true or false
复制代码

02-检查日期是否为周末

通过此功能,您将能够检查提供的日期是工作日还是周末。

const isWeekend = (date) => [0, 6].indexOf(date.getDay()) !== -1;

console.log(isWeekend(new Date(2021, 4, 14)));
// false (Friday)
console.log(isWeekend(new Date(2021, 4, 15)));
// true (Saturday)
复制代码

03-检查数字是偶数还是奇数

简单的实用程序功能,用于检查数字是偶数还是奇数。

const isEven = (num) => num % 2 === 0;

console.log(isEven(5));
// false
console.log(isEven(4));
// true
复制代码

04-获取数组中的唯一值

从数组中删除所有重复值的非常简单的方法。此函数将数组转换为Set,然后返回数组。

const uniqueArr = (arr) => [...new Set(arr)];

console.log(uniqueArr([1, 2, 3, 1, 2, 3, 4, 5]));
// [1, 2, 3, 4, 5]
复制代码

05-检查变量是否为数组

一种检查变量是否为数组的干净简便的方法。

好吧,也可以有其他方法😉

const isArray = (arr) => Array.isArray(arr);

console.log(isArray([1, 2, 3]));
// true
console.log(isArray({ name: 'Ovi' }));
// false
console.log(isArray('Hello World'));
// false
复制代码

06-在两个数字之间生成一个随机数

这将以两个数字为参数,并将在这两个数字之间生成一个随机数!

const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);

console.log(random(1, 50));
// could be anything from 1 - 50
复制代码

07-生成随机字符串(唯一ID?)

也许您需要为某个东西创建一个临时的唯一ID,这是一个技巧,您可以使用它在旅途中生成随机字符串。

这里是通过**Math.random** 和 **toString** 来实现并生成

-   `Math.random()`可以生成一个(0, 1)区间的随机数
-   `toString`方法可以将数字转化为`radix`进制的字符串
const randomString = () => Math.random().toString(36).slice(2);
console.log(Math.random().toString(24)) // 0.njk5d6i1l5
console.log(Math.random().toString(24).substring(2))//njk5d6i1l5
console.log(randomString());
// could be anything!!!
console.log(Math.random()) // 0.32442092439190673
console.log(Math.random()) // 0.56735456229190673

console.log(Math.random().toString(24)) // 0.njk5d6i1l5

// 接下来我们使用substring方法来截取一下,看下面的操作
console.log(Math.random().toString(24).substring(2)) // 现在输出以后会变成 njk5d6i1l5

08-滚动到页面顶部

所述window.scrollTo()方法把一个Xÿ坐标滚动到。 如果将它们设置为零和零,则将滚动到页面顶部。

const scrollToTop = () => window.scrollTo(0, 0);

scrollToTop();
复制代码

09-切换布尔

切换布尔值是非常基本的编程问题之一,可以通过许多不同的方法来解决。 代替使用if语句来确定将布尔值设置为哪个值,您可以使用函数使用*!翻转当前值。*“非”运算符。

// bool is stored somewhere in the upperscope
const toggleBool = () => (bool = !bool);
复制代码

10-交换两个变量

以下代码是不使用第三个变量而仅使用一行代码即可交换两个变量的更简单方法之一。

[foo, bar] = [bar, foo];
复制代码

11-计算两个日期之间的天数

要计算两个日期之间的天数, 我们首先找到两个日期之间的绝对值,然后将其除以86400000(等于一天中的毫秒数),最后将结果四舍五入并返回。

const daysDiff = (date, date2) => Math.ceil(Math.abs(date - date2) / 86400000);

console.log(daysDiff(new Date('2021-05-10'), new Date('2021-11-25')));
// 199
复制代码

12-将文字复制到剪贴板

PS:您可能需要添加检查以查看是否存在navigator.clipboard.writeText

const copyTextToClipboard = async (text) => {
  await navigator.clipboard.writeText(text);
};
复制代码

13-合并多个数组的不同方法

有两种合并数组的方法。其中之一是使用“ concat”方法。另一个正在使用扩展运算符(“…”)。

PS:我们也可以使用“设置”对象从最终数组中复制任何内容。

// Merge but don't remove the duplications
const merge = (a, b) => a.concat(b);
// Or
const merge = (a, b) => [...a, ...b];

// Merge and remove the duplications
const merge = [...new Set(a.concat(b))];
// Or
const merge = [...new Set([...a, ...b])];
复制代码

14-获取javascript原语的实际类型

人们有时会使用库来查找JavaScript中某些内容的实际类型,这一小技巧可以节省您的时间(和代码大小)。

const trueTypeOf = (obj) => {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
};

console.log(trueTypeOf(''));
// string
console.log(trueTypeOf(0));
// number
console.log(trueTypeOf());
// undefined
console.log(trueTypeOf(null));
// null
console.log(trueTypeOf({}));
// object
console.log(trueTypeOf([]));
// array
console.log(trueTypeOf(0));
// number
console.log(trueTypeOf(() => {}));
// function
复制代码

15-在结尾处截断字符串

需要从头开始截断字符串,这不是问题!

const truncateString = (string, length) => {
  return string.length < length ? string : `${string.slice(0, length - 3)}...`;
};

console.log(
  truncateString('Hi, I should be truncated because I am too loooong!', 36),
);
// Hi, I should be truncated because...
复制代码

16-从中间截断字符串

从中间截断字符串怎么样?

该函数将一个字符串作为第一个参数,然后将我们需要的字符串大小作为第二个参数,然后从第3个和第4个参数开始和结束需要多少个字符。

const truncateStringMiddle = (string, length, start, end) => {
  return `${string.slice(0, start)}...${string.slice(string.length - end)}`;
};

console.log(
  truncateStringMiddle(
    'A long story goes here but then eventually ends!', // string
    25, // total size needed
    13, // chars to keep from start
    17, // chars to keep from end
  ),
);
// A long story ... eventually ends!
复制代码

17-大写字符串

好吧,不幸的是,JavaScript没有内置函数来大写字符串,但是这种解决方法可以帮助您实现目标。

const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);

console.log(capitalize('hello world'));
// Hello world
复制代码

18-检查当前选项卡是否在视图/焦点内

此简单的帮助程序方法根据选项卡是否处于视图/焦点状态而返回true或false

const isTabInView = () => !document.hidden;  // Not hidden

isTabInView();
// true/false
复制代码

19-检查用户是否在Apple设备上(做兼容时判断设备系统)

如果用户使用的是Apple设备,则返回true

const isAppleDevice = () => /Mac|iPod|iPhone|iPad/.test(navigator.platform);

console.log(isAppleDevice);
// true/false
复制代码

20-三元运算符

当您只想在一行中编写if..else语句时,这是一个很好的代码保护程序。

// Longhand
const age = 18;
let greetings;

if (age < 18) {
  greetings = 'You are not old enough';
} else {
  greetings = 'You are young!';
}

// Shorthand
const greetings = age < 18 ? 'You are not old enough' : 'You are young!';
复制代码

奖金-短路评估速记

在将变量值分配给另一个变量时,您可能需要确保源变量不为null,未定义或为空。 您可以编写带有多个条件的long if语句,也可以使用短路评估。

// Longhand
if (name !== null || name !== undefined || name !== '') {
  let fullName = name;
}

// Shorthand
const fullName = name || 'buddy';
复制代码

计算距离下次生日还有多少天

注意这里借助 moment 实现

    getBirthdayFun(){
       // 首先要获取到今年的生日
      let birthdayTime = moment().format('YYYY-') + '12-19'
      // 通过时间戳  去判断当前的时间戳是否大于今年生日的时间戳 
      if (moment().unix() >= moment(birthdayTime).unix()) {
        // 如果大于的话,那么就在今年的生日上再添加一年,已达到获取下次生日的时间
        birthdayTime = moment(birthdayTime).add(1, 'y').format('YYYY-MM-DD')
      }
      // 这个直接通过计算 (下次生日的时间戳 - 当前日期的时间戳) / (60 * 60 * 24) 最后求出来的就是 XX 天
      return parseInt(
        (moment(birthdayTime).unix() - moment().unix()) / (60 * 60 * 24)
      )
    }
复制代码

回到顶部

    // 这里我把 vue3 的案例拿过来
    const bindTop = () => {
       // 方法一 这样可以实现,但是效果不太行
       window.scrollTo(0, 0)
       document.documentElement.scrollTop = 0;
        
      // 方法二 通过计时器去滚动 视觉上会丝滑一些,没有太大的卡顿效果
      const timeTop = setInterval(() => {
        // 去控制他的滑行距离
        document.documentElement.scrollTop = scrollTopH.value -= 50
        // 当滑到顶部的时候记得清除计时器(*) 重点
        if (scrollTopH.value <= 0) {
          clearInterval(timeTop)
        }
      }, 10)
    }


window.scrollTo({
top:0,
behavior: 'smooth'
})
而且behavior: 'smooth'写在css里面,锚点跳转,router跳转后回调顶部都是有效果的,挺好用

复制文本

    const copyText = (text) => {
        // clipboardData 在页面上将需要的东西复制到剪贴板上
        const clipboardData = window.clipboardData
        if (clipboardData) {
          clipboardData.clearData()
          clipboardData.setData('Text', text)
          return true
        } else if (document.execCommand) {  // 注意 document.execCommand 已弃用 但是有些浏览器依旧支持 用的时候记得看兼容情况
          // 通过创建 dom 元素,去把要复制的内容拿到 
          const el = document.createElement('textarea')
          el.value = text
          el.setAttribute('readonly', '')
          el.style.position = 'absolute'
          el.style.left = '-9999px'
          document.body.appendChild(el)
          el.select()
          // 拷贝当前内容到剪贴板
          document.execCommand('copy')
          // 删除 el 节点
          document.body.removeChild(el)
          return true
        }
        return false
      }
      copyText('hello!') // ctrl + v = copyText  | true
复制代码
复制代码

防抖/节流

简单介绍

  • 防抖:指定时间内 频繁触发一个事件,以最后一次触发为准
  • 节流:指定时间内 频繁触发一个事件,只会触发一次

应用场景有很多比如:

防抖是: input搜索,用户在不断输入内容的时候,用防抖来减少请求的次数并且节约请求资源

节流:场景普遍就是按钮点击,一秒点击 10 下会发起 10 次请求,节流以后 1 秒点再多次,都只会触发一次

下面我们来实现

    // 防抖
    // fn 需要防抖的函数,delay 为定时器时间
    function debounce(fn,delay){
        let timer =  null  // 用于保存定时器
        return function () { 
            // 如果timer存在 就清除定时器,重新计时
            if(timer){
                clearTimeout(timeout);
            }
            //设置定时器,规定时间后执行真实要执行的函数
            timeout = setTimeout(() => {
               fn.apply(this);
            }, delay);
        }
    }
    
    // 节流
    function throttle(fn) {
      let timer = null; // 首先设定一个变量,没有执行定时器时,默认为 null
      return function () {
        if (timer) return; // 当定时器没有执行的时候timer永远是false,后面无需执行
        timer = setTimeout(() => {
          fn.apply(this, arguments);
           // 最后在setTimeout执行完毕后再把标记设置为true(关键)
           // 表示可以执行下一次循环了。
          timer = null;
        }, 1000);
      };
    }
复制代码

过滤特殊字符

    function filterCharacter(str){
        // 首先设置一个模式
        let pattern = new RegExp("[`~!@#$^&*()=:”“'。,、?|{}':;'%,\[\].<>/?~!@#¥……&*()&;—|{ }【】‘;]")
        let resultStr = "";
        for (let i = 0; i < str.length; i++) {
            // 主要通过 replace ,pattern 规则 去把字符替换成空 最后拼接在 resultStr
            resultStr = resultStr + str.substr(i, 1).replace(pattern, '');
        }
        // 当循环结束的时候返回最后结果 resultStr
        return resultStr;
    }
    
    // 示例
    filterCharacter('gyaskjdhy12316789#$%^&!@#1=123,./[') // 结果:gyaskjdhy123167891123
复制代码

常用正则判断

    // 校验2-9位文字 不符合为 false  符合为 true
    const validateName = (name) => {
      const reg = /^[\u4e00-\u9fa5]{2,9}$/;
      return reg.test(name);
    };

    // 校验手机号
    const validatePhoneNum = (mobile) => {
      const reg = /^1[3,4,5,6,7,8,9]\d{9}$/;
      return reg.test(mobile);
    };

    // 校验6到18位大小写字母数字下划线组成的密码
    const validatePassword = (password) => {
      const reg = /^[a-zA-Z0-9_]{6,18}$/;
      return reg.test(password);
    };
复制代码

初始化数组

    // fill()方法 是 es6新增的一个方法 使用指定的元素填充数组,其实就是用默认内容初始化数组
    const arrList = Array(6).fill()
    console.log(arrList)  // 此处打印的是 ['','','','','','']
复制代码

将 RGB 转换为十六进制

    function getColorFun(r,g,b) {
       return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
    }
    
    getColorFun(178,232,55) // 这里输出的是 #b2e837
复制代码

检测是否是一个函数


    // 检测是否是一个函数  其实写法以后直接 isFunction 就好了,避免重复写判断
    const isFunction = (obj) => {
        return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function";
    };

这个简单些 Object.prototype.toString.call(obj).slice(8,-1) === 'Function'

检测是否为一个安全数组

  // 检测是否为一个安全数组,若不是返回空数组  这里借助isArray 方法
  const safeArray = (array) => {
    return Array.isArray(array) ? array : []
  }
复制代码

检测对象是否为一个安全对象

    // 首先要去判断 当前对象是否为有效对象 
    const isVaildObject = (obj) => {
        return typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length
    }
    // 这里直接用上面的函数 如果有效就返回本身,无效就返回空对象
    const safeObject = obj => isVaildObject(obj) ? obj : {}
    
复制代码