日常开发中,面对各种不同的需求,我们经常会用到以前开发过的一些工具函数,把这些工具函数收集起来,将大大提高我们的开发效率 示例: 示例: 如 vue 中使用 参数: 示例: 示例: 参数: 示例: 示例: 示例: ::: warning 注意 不过,uuid一般应由后端来进行生成 ::: 参数: 示例: setItem(key, value) { getItem(key) { removeItem(key) { clear() { key(index) { length() { const localCache = new MyCache() 示例: 参数: 关于时间操作,没必要自己再写一大串代码了,推荐使用 在 JavaScript 中解析、校验、操作、显示日期和时间。 格式化日期 相对时间 日历时间 多语言环境支持 Day.js 是一个仅 2kb 大小的轻量级 JavaScript 时间日期处理库,下载、解析和执行的JavaScript更少,为代码留下更多的时间。 // 处理正则 const _clone = parent => { let child, proto; if (isType(parent, "Array")) { // 处理循环引用 if (index != -1) { for (let i in parent) { 此方法存在一定局限性:一些特殊情况没有处理: 例如Buffer对象、Promise、Set、Map。 如果确实想要完备的深拷贝,推荐使用 lodash 中的 cloneDeep 方法。 参数: 示例: 示例: 假设我们要从树状结构数据中查找 id 为 9 的节点 例如:根据id是否相等? 更新数组对象中的某个对象,如果相等就更新,不相等就push进去 const newObject1 = { id: 2, name: 'NewObj1' }; const updatedArray1 = replaceObjectById(array, newObject1); 当我们需要一个唯一id时,通过Math.random创建一个随机字符串简直不要太方便噢!!! 解决XSS方法之一就是转义HTML。 得益于ES6,使用Set数据类型来对数组去重太方便了JavaScript工具函数助力高效开发
前言
1. 校验数据类型
export const typeOf = function(obj) {
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
typeOf(new Date()) // date
typeOf(null) // null
typeOf(true) // boolean
typeOf(() => { }) // function
typeOf('前端圈子') // string
typeOf([]) // array
2. 防抖
export const debounce = (() => {
let timer = null
return (callback, wait = 800) => {
timer&&clearTimeout(timer)
timer = setTimeout(callback, wait)
}
})()
methods: {
loadList() {
debounce(() => {
console.log('加载数据')
}, 500)
}
}
3. 节流
export const throttle = (() => {
let last = 0
return (callback, wait = 800) => {
let now = +new Date()
if (now - last > wait) {
callback()
last = now
}
}
})()
4. 手机号脱敏
export const hideMobile = (mobile) => {
return mobile.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2")
}
5. 开启全屏
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()
}
}
6. 关闭全屏
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()
}
}
7. 大小写转换
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
8. 解析URL参数
export const getSearchParams = () => {
const searchPar = new URLSearchParams(window.location.search)
const paramsObj = {}
for (const [key, value] of searchPar.entries()) {
paramsObj[key] = value
}
return paramsObj
}
// 假设目前位于 https://****com/index?id=154513&age=18;
getSearchParams(); // {id: "154513", age: "18"}
9. 判断手机是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;
}
10. 数组对象根据字段去重
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: 'UI设计师' },
{ id: 3, name: '前端' },
{ id: 1, name: '后端' },
{ id: 2, name: '测试' },
{ id: 3, name: '产品经理' },
]
uniqueArrayObject(responseList, 'id')
// [{ id: 1, name: '前端' },{ id: 2, name: '后端' },{ id: 3, name: '测试' }]11. 滚动到页面顶部
export const scrollToTop = () => {
const height = document.documentElement.scrollTop || document.body.scrollTop;
if (height > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, height - height / 8);
}
}
12. 滚动到元素位置
export const smoothScroll = element =>{
document.querySelector(element).scrollIntoView({
behavior: 'smooth'
});
};
smoothScroll('#target'); // 平滑滚动到 ID 为 target 的元素
13. 生成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
14、金额格式化
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
15、存储操作
class MyCache {
constructor(isLocal = true) {
this.storage = isLocal ? localStorage : sessionStorage
}
if (typeof (value) === 'object') value = JSON.stringify(value)
this.storage.setItem(key, value)
}
try {
return JSON.parse(this.storage.getItem(key))
} catch (err) {
return this.storage.getItem(key)
}
}
this.storage.removeItem(key)
}
this.storage.clear()
}
return this.storage.key(index)
}
return this.storage.length
}
}
const sessionCache = new MyCache(false)export { localCache, sessionCache }
localCache.getItem('user')
sessionCache.setItem('name','前端圈子')
sessionCache.getItem('token')
localCache.clear()
16、下载文件
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}, '文件名')
17、时间操作
Moment.js
和 Day.js
Moment.js
<script src="https://cdn.bootcdn.net/ajax/libs/react/18.2.0/cjs/react-jsx-dev-runtime.development.min.js"></script>
npm install moment --save # npm
yarn add moment # Yarn
moment().format('MMMM Do YYYY, h:mm:ss a'); // 十一月 5日 2023, 12:33:14 下午
moment().format('dddd'); // 星期日
moment().format("MMM Do YY"); // 11月 5日 23
moment().format('YYYY [escaped] YYYY'); // 2023 escaped 2023
moment().format(); // 2023-11-05T12:33:14+08:00
moment("20111031", "YYYYMMDD").fromNow(); // 12 年前
moment("20120620", "YYYYMMDD").fromNow(); // 11 年前
moment().startOf('day').fromNow(); // 13 小时前
moment().endOf('day').fromNow(); // 11 小时后
moment().startOf('hour').fromNow(); // 33 分钟前
moment().subtract(10, 'days').calendar(); // 2023/10/26
moment().subtract(6, 'days').calendar(); // 本周一12:33
moment().subtract(3, 'days').calendar(); // 本周四12:33
moment().subtract(1, 'days').calendar(); // 昨天12:33
moment().calendar(); // 今天12:33
moment().add(1, 'days').calendar(); // 明天12:33
moment().add(3, 'days').calendar(); // 下周三12:33
moment().add(10, 'days').calendar(); // 2023/11/15
moment.locale(); // zh-cn
moment().format('LT'); // 12:33
moment().format('LTS'); // 12:33:14
moment().format('L'); // 2023/11/05
moment().format('l'); // 2023/11/5
moment().format('LL'); // 2023年11月5日
moment().format('ll'); // 2023年11月5日
moment().format('LLL'); // 2023年11月5日下午12点33分
moment().format('lll'); // 2023年11月5日 12:33
moment().format('LLLL'); // 2023年11月5日星期日下午12点33分
moment().format('llll');
Day.js
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.9/dayjs.min.js"></script>
npm install dayjs --save # npm
yarn add dayjs # Yarn
cnpm install dayjs -S # cnpm
pnpm add dayjs # pnpm
var dayjs = require('dayjs')
// import dayjs from 'dayjs' // ES 2015
dayjs().format()
dayjs().format(); // 2020-09-08T13:42:32+08:00
dayjs().format('YYYY-MM-DD'); // 2020-09-08
dayjs().format('YYYY-MM-DD HH:mm:ss'); // 2020-09-08 13:47:12
dayjs(1318781876406).format('YYYY-MM-DD HH:mm:ss'); // 2011-10-17 00:17:56
18、深拷贝
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 = [];
if (parent = null) return null;
if (typeof parent ! "object") return parent;
// 对数组做特殊处理
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);
// 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象
return children[index];
}
parents.push(parent);
children.push(child);
// 递归
child[i] = _clone(parent[i]);
} return child;
};
return _clone(parent);
};
19、模糊搜索
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: 'UI设计师' },
]
fuzzyQuery(list, '前', 'name') // [{id: 1, name: '树哥'}]
20. 遍历树节点
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)
}
}
}
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"} 21.数组对象根据某个元素的某个属性去判断原数组是更新还是push
// 方法
function replaceObjectById(array, newObject) {
const id = newObject.id;
let isReplaced = false;
const newArray = array.map(obj => {
if (obj.id === id) {
isReplaced = true;
return newObject;
}
return obj;
});
if (!isReplaced) {
newArray.push(newObject);
}
return newArray;
}
// 使用
const array = [
{ id: 1, name: 'Obj1' },
{ id: 2, name: 'Obj2' },
{ id: 3, name: 'Obj3' }
];
const newObject2 = { id: 4, name: 'NewObj2' };
console.log(updatedArray1);
// 输出: [ { id: 1, name: 'Obj1' }, { id: 2, name: 'NewObj1' }, { id: 3, name: 'Obj3' } ]const updatedArray2 = replaceObjectById(array, newObject2);
console.log(updatedArray2);
// 输出: [ { id: 1, name: 'Obj1' }, { id: 2, name: 'Obj2' }, { id: 3, name: 'Obj3' }, { id: 4, name: 'NewObj2' } ]22.生成随机字符串
const randomString = () => Math.random().toString(36).slice(2)
randomString() // gi1qtdego0b
randomString() // f3qixv40mot
randomString() // eeelv1pm3ja
23.转义HTML特殊字符
const escape = (str) => str.replace(/[&<>"']/g, (m) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m]))
escape('<div class="medium">Hi Medium.</div>')
// <div class="medium">Hi Medium.</div>
24.单词首字母大写
const uppercaseWords = (str) => str.replace(/^(.)|\s+(.)/g, (c) => c.toUpperCase())
uppercaseWords('hello world'); // 'Hello World'
25.将字符串转换为小驼峰
const toCamelCase = (str) => str.trim().replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''));
toCamelCase('background-color'); // backgroundColor
toCamelCase('-webkit-scrollbar-thumb'); // WebkitScrollbarThumb
toCamelCase('_hello_world'); // HelloWorld
toCamelCase('hello_world'); // helloWorld
26.转义HTML特殊字符
const removeDuplicates = (arr) => [...new Set(arr)]
console.log(removeDuplicates([1, 2, 2, 3, 3, 4, 4, 5, 5, 6]))
// [1, 2, 3, 4, 5, 6]
27.铺平一个数组
const flat = (arr) =>
[].concat.apply(
[],
arr.map((a) => (Array.isArray(a) ? flat(a) : a))
)
// Or
const flat = (arr) => arr.reduce((a, b) => (Array.isArray(b) ? [...a, ...flat(b)] : [...a, b]), [])
flat(['cat', ['lion', 'tiger']]) // ['cat', 'lion', 'tiger']
28.移除数组中的假值
const removeFalsy = (arr) => arr.filter(Boolean)
removeFalsy([0, 'a string', '', NaN, true, 5, undefined, 'another string', false])
// ['a string', true, 5, 'another string']
29.确认一个数字是奇数还是偶数
const isEven = num => num % 2 === 0
isEven(2) // true
isEven(1) // false
30.获取两个数字之间的随机数
const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
random(1, 50) // 25
random(1, 50) // 34
31.计算平均值
const average = (...args) => args.reduce((a, b) => a + b) / args.length;
average(1, 2, 3, 4, 5); // 3
32.将数字截断到固定的小数点
const round = (n, d) => Number(Math.round(n + "e" + d) + "e-" + d)
round(1.005, 2) //1.01
round(1.555, 2) //1.56
33.计算两个日期之间天数
const diffDays = (date, otherDate) => Math.ceil(Math.abs(date - otherDate) / (1000 * 60 * 60 * 24));
diffDays(new Date("2021-11-3"), new Date("2022-2-1")) // 90
34.从日期中获取是一年中的哪一天
const dayOfYear = (date) => Math.floor((date - new Date(date.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24))
dayOfYear(new Date()) // 74
35.获取一个随机的颜色值
const randomColor = () => `#${Math.random().toString(16).slice(2, 8).padEnd(6, '0')}`
randomColor() // #9dae4f
randomColor() // #6ef10e
36.将RGB颜色转换为十六进制颜色值
const rgbToHex = (r, g, b) => "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
rgbToHex(255, 255, 255) // '#ffffff'
37.清除所有的cookie
const clearCookies = () => document.cookie.split(';').forEach((c) => (document.cookie = c.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`)))
38.检测黑暗模式
const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
39.交换两个变量的值
[foo, bar] = [bar, foo]
40.暂停一会
const pause = (millis) => new Promise(resolve => setTimeout(resolve, millis))
const fn = async () => {
await pause(1000)
console.log('fatfish') // 1s later
}
fn()
41.JS适配rem
// 调用
getFontSize();
<style>
/使用方式很简单,比如效果图上,有张图片。宽高都是100px;/
/样式写法就是/
img{
width:1rem;
height:1rem;
}
/这样的设置,比如在屏幕宽度大于等于750px设备上,1rem=100px;图片显示就是宽高都是100px/
/比如在iphone6(屏幕宽度:375)上,375/750100=50px;就是1rem=50px;图片显示就是宽高都是50px;*/
</style>/**
* JS适配rem
*/
function getFontSize(){
var doc=document,win=window;
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
//如果屏幕大于750(750是根据我效果图设置的,具体数值参考效果图),就设置clientWidth=750,防止font-size会超过100px
if(clientWidth>750){clientWidth=750}
//设置根元素font-size大小
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
};
//屏幕大小改变,或者横竖屏切换时,触发函数
win.addEventListener(resizeEvt, recalc, false);
//文档加载完成时,触发函数
doc.addEventListener('DOMContentLoaded', recalc, false);
}
42.JS判断浏览器
/**
* JS判断浏览器
* @returns {string}
*/
function getBrowserName () {
if (navigator.userAgent.indexOf("MSIE 8.0") > 0) {
return "MSIE8";
} else if (navigator.userAgent.indexOf("MSIE 6.0") > 0) {
return "MSIE6";
} else if (navigator.userAgent.indexOf("MSIE 7.0") > 0) {
return "MSIE7";
} else if (isFirefox = navigator.userAgent.indexOf("Firefox") > 0) {
return "Firefox";
}
if (navigator.userAgent.indexOf("Chrome") > 0) {
return "Chrome";
} else {
return "Other";
}
}
43.JS判断两个数组是否相等
/**
* @param {Array} arr1
* @param {Array} arr2
* @returns {boolean} 返回true 或 false
*/
function arrayEqual(arr1, arr2) {
if (arr1 === arr2) return true;
if (arr1.length != arr2.length) return false;
for (var i = 0; i < arr1.length; ++i) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
44.JS验证手机格式
// 调用方法:
verifyPhoneNumber('18412345678')
/**
* @param str 对应手机号码
* @returns {boolean} 结果返回 true 和 false。
* true 为正确手机号码
* false 为错误手机号码
*/
function verifyPhoneNumber(str){
var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
return myreg.test(str);
}
45.获取地址栏参数的值
// 若当前的URL地址为:a.html?t1=1&t2=2&t3=3
console.log(getUrlParam("t1")); // 1
/**
* JS获取地址栏参数的值
* @param name 对应的参数
* @returns {*} 如果有,则返回参数值,没有则返回null
*/
function getUrlParam(name){
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
} else {
return null;
}
}
46.检查输入的字符是否具有特殊字符
checkQuote("dasd1!/,/."); // true
checkQuote("52014sdsda"); // false
/**
* JS检查输入的字符是否具有特殊字符
* @param str 字符串
* @returns true 或 false; true表示包含特殊字符 主要用于注册信息的时候验证
*/
function checkQuote(str) {
var items = new Array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "{", "}", "[", "]", "(", ")");
items.push(":", ";", "'", "|", "\", "<", ">", "?", "/", "<<", ">>", "||", "//");
items.push("select", "delete", "update", "insert", "create", "drop", "alter", "trancate");
str = str.toLowerCase();
for ( var i = 0; i < items.length; i++) {
if (str.indexOf(items[i]) >= 0) {
return true;
}
}
return false;
}
47.JS判断是否为空
/**
* JS判断是否为空
* @param val
* @returns {boolean}
*/
function isNull(val) {
if (val == undefined || val == null || val == "") {
return true;
}
return false;
}