JavaScript 工具方法

处理 ant 下拉问题

    :getPopupContainer="(triggerNode) => triggerNode.parentNode"

JavaScript blob 类型转 file 类型

var blob = new Blob(byteArrays, { type: contentType });
//blob转file
var file = new File([blob], filename, {
  type: contentType,
  lastModified: Date.now(),
});
//或者
var file = new File([byteArrays], filename, {
  type: contentType,
  lastModified: Date.now(),
});

类型判断

Object.prototype.toString.call('')  // [object String]
Object.prototype.toString.call([]) // [object Array]
ct.prototype.toString.call(new Date()) //[object Date]
Object.prototype.toString.call(/ds/) // [object RegExp]
.....

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

    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);
};

防抖/节流

// 防抖
// 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); // 此处打印的是 ['','','','','','']

或者;

const arrList = Array.from(Array(6));

将 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"
  );
};

检测是否为一个安全数组

// 检测是否为一个安全数组,若不是返回空数组  这里借助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 : {});

js 的一个 post 跳转提交

openPostWindow(
  "/costOrderExcel",
  JSON.stringify({
    ids: ids,
    date_type: date_type,
    start_date: startDate,
    end_date: endDate,
  })
);

function openPostWindow(url, data1) {
  var tempForm = document.createElement("form");
  tempForm.id = "tempForm1";
  tempForm.method = "post";
  tempForm.action = url;
  tempForm.target = "_blank"; //打开新页面
  var hideInput1 = document.createElement("input");
  hideInput1.type = "hidden";
  hideInput1.name = "data"; //后台要接受这个参数来取值
  hideInput1.value = data1; //后台实际取到的值
  tempForm.appendChild(hideInput1);
  if (document.all) {
    tempForm.attachEvent("onsubmit", function () {}); //IE
  } else {
    var subObj = tempForm.addEventListener("submit", function () {}, false); //firefox
  }
  document.body.appendChild(tempForm);
  if (document.all) {
    tempForm.fireEvent("onsubmit");
  } else {
    tempForm.dispatchEvent(new Event("submit"));
  }
  tempForm.submit();
  document.body.removeChild(tempForm);
}

js 等待 sleep

//sleep
export function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

https://juejin.cn/post/6844903521930870792open in new window

大小写转换

<body>
  <h2></h2>
  <div class="div"></div>
</body>
<script>
  let str = "Hello World!";
  document.querySelector("h2").innerHTML = str;
  let btns = document.querySelectorAll("button");
  const str2 = "asdf sfds  fdsfds ";
  const resultStr = str2
    .split(" ")
    .map((item) => {
      return (
        (item && item[0] && item[0].toUpperCase()) +
        (item.substr(1) && item.substr(1).toLowerCase())
      );
    })
    .join(" ");
  document.querySelector(".div").innerHTML = resultStr;
</script>

防抖

<body>
  <input type="text" value="123" />
  <button id="btn">提交</button>
</body>
<script>
  let btn = document.querySelector("#btn");
  let ipt = document.querySelector("input");
  const debounce = (() => {
    let timer = null;
    return (callback, time = 800) => {
      timer && clearTimeout(timer);
      timer = setTimeout(callback, time);
    };
  })();
  btn.addEventListener("click", function () {
    //防抖 在一定时间间隔内最多只触发一次
    debounce(() => {
      console.log(1);
      console.log(ipt.value);
    }, 2000);
  });
  //使用场景
  //登录
  //短信发送
  //浏览器大小变化(大小计算)
  //搜索框输入
</script>

滚动到对应元素位置

<style>
  .box {
    width: 500px;
    height: 1200px;
    border: 10px solid pink;
  }
</style>
<body>
  <div class="box"></div>
  <h2>你好</h2>
  <div class="box"></div>
  <button>回到顶部</button>
</body>
<script>
  const scrollElement = (element) => {
    //scrollIntoView 将调用的元素 滚动到浏览器的可见区域
    //behavior 过度动画
    document.querySelector(element).scrollIntoView({ behavior: "smooth" });
  };
  document.querySelector("button").addEventListener("click", function () {
    // 滚动到元素指定位置
    scrollElement("h2");
  });
</script>

滚动到页面顶部

<style>
  .box {
    width: 500px;
    height: 1200px;
    border: 10px solid pink;
  }
</style>
<body>
  <div class="box"></div>
  <button>回到顶部</button>
</body>
<script>
  let btn = document.querySelector("button");
  const scrollTop = () => {
    //获取滚动条高度
    const height =
      document.documentElement.scrollTop || document.body.scrollTop;
    if (height > 10) {
      // 动画效果 当浏览器在每一次重绘的时候就会调用这个方法
      window.requestAnimationFrame(scrollTop);
      //将内容滚动到指定坐标
      window.scrollTo(0, height - height / 8);
    }
  };
  btn.addEventListener("click", scrollTop);
</script>

获取当前时间

<script>
  // 获取当前时间
  function getTime(date = new Date()) {
    // 获取年份
    var y = date.getFullYear();
    //获取月份  1-01    0-11
    var m = date.getMonth() + 1;
    m = m < 10 ? "0" + m : m;
    //获取天数
    var d = date.getDate();
    d = d < 10 ? "0" + d : d;
    return y + "/" + m + "/" + d;
  }
  console.log(getTime());

  // 获取当前月的第一天 和最后一天
  function getFirstLastDay() {
    var now = new Date(); //当前日期
    var y = now.getFullYear(); //当前年
    var m = now.getMonth(); //当前月
    var firstDay = new Date(y, m, 1); //本月开始的时间
    var lastDay = new Date(y, m + 1, 0); //本月的最后一天
    firstDay = firstDay.getMonth() + 1 + "/" + "0" + firstDay.getDate();
    lastDay = lastDay.getMonth() + 1 + "/" + lastDay.getDate();
    return { firstDay, lastDay };
  }
  console.log(getFirstLastDay());
</script>

节流

<body>
  <input type="text" value="111" />
</body>
<script>
  // 节流 减少一段时间的触发频率
  // 方法一
  let ipt = document.querySelector("input");
  const throttle = (() => {
    let last = 0;
    return (callback, time = 800) => {
      let now = +new Date();
      if (now - last > time) {
        callback();
        last = now;
      }
    };
  })();

  const throttle2 = (() => {
    let mark = true;
    return (callback, time = 800) => {
      if (mark) {
        mark = false;
        setTimeout(() => {
          mark = true;
        }, time);
        callback();
      }
    };
  })();

  ipt.addEventListener("input", function () {
    if (ipt.value == "") {
      return;
    }
    throttle2(() => {
      console.log(ipt.value);
    }, 2000);
  });
  // 使用场景
  // 1 scroll 时间每隔一秒计算一次位置信息等
  // 2 input 框实时搜索并发送请求展示下拉列表,也可以做防抖
</script>

模糊查询

<body>
  <input type="text" />
  <button>搜索</button>
</body>
<script>
  //模糊查询
  var ipt = document.querySelector("input");
  var btn = document.querySelector("button");
  const searchQuery = (list, keyword, attr = "name") => {
    const reg = new RegExp(keyword);
    const arr = []; //接收匹配到的内容
    list.forEach((item) => {
      if (reg.test(item[attr])) {
        arr.push(item);
      }
    });
    return arr;
  };
  const list = [
    { id: 1, name: "张山" },
    { id: 5, name: "张山1" },
    { id: 2, name: "李四" },
    { id: 3, name: "王五" },
    { id: 4, name: "小帅" },
  ];
  btn.addEventListener("click", function () {
    const re = searchQuery(list, ipt.value, "name");
    console.log(re);
  });
</script>

数组去重

<script>
  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;
      }
    });
    return Object.values(map);
  };
  const responseList = [
    {
      id: 1,
      name: "111111",
    },
    {
      id: 1,
      name: "1111",
    },
    {
      id: 2,
      name: "2222222",
    },
    {
      id: 1,
      name: "111111",
    },
  ];
  const re = uniqueArrayObject(responseList, "id");
  console.log(re);
</script>

文件下载

const blob = new Blob([二进制文件], { type: "application/octet-stream" });
saveAsByBlob(fileName, blob);
function saveAsByBlob(fileName: string, blob: Blob) {
  const link = c(fileName);
  const url = URL.createObjectURL(blob);
  link.href = url;
  setTimeout(() => {
    link.click();
  }, 0);
  setTimeout(() => {
    URL.revokeObjectURL(url);
  }, 3e5);
}
function getLinkElem(download: string) {
  const link = document.createElement("a");
  const name = download || "download";
  link.rel = "noopener";
  link.setAttribute("download", name);
  return link;
}

深度拷贝

const toString = Object.prototype.toString;

/**
 * 深度拷贝
 * @param source 源对象
 * @param cache 标记已复制对象,防止循环引用
 * @returns
 */
export default function cloneDeep(source: any, cache = new WeakMap()): any {
  if (typeof source !== "object" || source === null) {
    return source;
  }

  const resCache = cache.get(source);
  if (resCache) {
    return resCache;
  }
  const dataType = toString.call(source).slice(8, -1).toLowerCase();
  const ctor = source.constructor;
  let res: any = null;
  switch (dataType) {
    case "number":
    case "string":
      res = new ctor(source);
      break;
    case "boolean":
    case "date":
      res = new ctor(source - 0);
      break;
    case "regexp":
      res = new ctor(source.source, source.flags);
      break;
    case "set":
    case "map":
    case "array":
    case "object":
      try {
        res = new ctor();
      } catch (_) {
        res = source;
      }
      break;
    default:
      res = source;
  }
  if (dataType === "set") {
    source.forEach((x: any) => {
      res.add(cloneDeep(x, cache));
    });
  } else if (dataType === "map") {
    Array.from(source.entries()).forEach((k, v) => {
      res.set(k, cloneDeep(v, cache));
    });
  } else if (dataType === "array" || dataType === "object") {
    // const oKeys = Object.getOwnPropertyNames(source).concat(Object.getOwnPropertySymbols(source));
    const oKeys = Reflect.ownKeys(source);
    for (const k of oKeys) {
      res[k] = cloneDeep(source[k], cache);
    }
  }
  cache.set(source, res);
  return res;
}

随机数 不包含 max

min+Math.floor(Math.random()*(Max-min))

const number = Math.floor(Math.random() * (5 - 2)) + 2;
console.log(number);

包含 max

min+Math.floor(Math.random()*(Max-min+1))

const number = Math.floor(Math.random() * (5 - 2 + 1)) + 2;
console.log(number);
Last Updated:
Contributors: 刘荣杰