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/6844903521930870792
大小写转换
<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);