# 工具函数系列
# From Vue
# From React
# From Angular
# From DOM
- 检测某个元素是否聚焦
const hasFocus = (el) => el === document.activeElement;
1
- 获取某个元素所有的兄弟元素
const a = (el) => [].slice.call(el.parentNode.children).filter((child) => child !== el);
1
- 获取当前选择的文本
const getSelectedText = () => window.getSelection().toString();
1
- 获取所有 cookie 并转为对象
const getCookies = () =>
document.cookie
.split(";")
.map((item) => item.split("="))
.reduce((acc, [k, v]) => (acc[k.trim().replace('"', "")] = v) && acc, {});
1
2
3
4
5
2
3
4
5
- 清除所有 cookie
const clearCookies = () => document.cookie
.split(';')
.forEach(c => document.cookie = c.splace(/^+/, '')
.replace(/=.*/,`=;expires=${new Date().toUTCString()};path=/`))
);
1
2
3
4
5
2
3
4
5
- 将 URL 参数转换为对象
const getUrlParams = (query) =>
Array.from(new URLSearchParams(query)).reduce(
(p, [k, v]) =>
Object.assign({}, p, {
[k]: p[k] ? (Array.isArray(p[k]) ? p[k] : [p[k]]).concat(v) : v,
}),
{}
);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 检测是否为暗模式
const isDarkMode = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
1
# From Array
- 比较两个数组
const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
1
- 将数组转为对象
const arrayToObject = (arr, key) => arr.reduce((a, b) => ({ ...a, [b[key]]: b }), {});
1
- 获取数组最后一个元素
// ES13
const lastItem = (arr) => arr.at(-1);
1
2
2
# From Object
- 检测多个对象是否相等
const isEqual = (...objects) => objects.every((obj) => JSON.stringify(obj) === JSON.stringify(objects[0]));
1
- 从对象数组中提取属性值
const pluck = (objs, property) => objs.map((obj) => obj[property]);
1
- 反转对象的 key/value
const invert = (obj) => Object.keys(obj).reduce((res, k) => Object.assign(res, { [obj[k]]: k }), {});
1
- 从对象中删除值为 null 和 undefined 的属性
const removeNullAndUndefined = (obj) =>
Object.entries(obj).reduce((a, [k, v]) => (v == null ? a : ((a[k] = v), a)), {});
1
2
2
- 按照对象的属性对对象排序
const sort = (obj) =>
Object.keys(obj)
.sort()
.reduce((p, c) => ((p[c] = obj[c]), p), {});
1
2
3
4
2
3
4
- 检测对象是否为数组
const isArray = (obj) => Array.isArray(obj);
1
- 检测对象是否为 Promise
const isPromise = (obj) =>
!!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
1
2
2
# From String
- 检查路径是否是相对路径
const isRelative = (path) => !/^([az]+:)?[\\/]/i.test(path);
1
- 生成 IP 地址
const randomIp = () =>
Array(4)
.fill(0)
.map((_, i) => Math.floor(Math.random() * 255) + (i === 0 ? 1 : 0))
.join(".");
1
2
3
4
5
2
3
4
5
- 生成十六进制颜色字符串
const randomColor = () => `#${Math.random().toString(16).slice(2, 8).padEnd(6, "0")}`;
1
- 生成 rgb 颜色字符串
const randomRgbColor = () =>
`rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`;
1
2
2
- 下划线转驼峰
const toHump = (str) => str.replace(/\_(\w)/g, (all, letter) => letter.toUpperCase());
1
- 驼峰转下划线横线
const toLine = (str) => str.replace(/([A-Z])/g, "_$1").toLowerCase();
1
- 检查字符串是否是十六进制颜色
const isHexColor = (color) => /^#([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$/i.test(color);
1
- RGB 字符串转十六进制字符串
const rgbToHex = (r, g, b) => "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
1
# From Date
- 两个日期之间相差的天数
const diffDays = (date, otherDate) => Math.ceil(Math.abs(date - otherDate) / (1000 * 60 * 60 * 24));
1
- 检查日期是否有效
const isDateValid = (...val) => !Number.isNaN(new Date(...val).valueOf());
1
- 检测代码是否处于 Node.js 环境
const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
1
- 检测代码是否处于浏览器环境
const isBrowser = typeof window === "object" && typeof document === "object";
1
# 正则匹配金额
// 匹配人民币
let [reg, info, rmb, result] = [
/^(¥)(-?[0-9,]+)(\.[0-9]+)?/,
["金额", "符号", "整数部分", "小数分部"],
["¥10.01", "¥10", "¥1,111.01", "¥1,000,12", "¥0.1", "¥10.00"],
];
rmb.forEach((value) => {
console.log("---------------------------------------------------------------------------------");
for (let i = 0, result = reg.exec(value); i < result.length; i++) {
console.log(`${info[i]} = ${result[i]}`);
}
});
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# js 替代 eval 方法
项目中遇到需要支持用户输入 js 并加以解析的场景。eval() 本身不太好,所以查找了下其他实现:
function new_eval(str) {
var fn = Function;
return new fn("return " + str)();
}
1
2
3
4
2
3
4
# 解析 16 进制序列为 UTF-8 字符
function decodeHexToUtf8(str: string, isJsonStr = false): string | object {
// 正则表达式,用于匹配形如 [0xe5] 的UTF-8编码序列
const hexPattern = /\[0x([0-9a-f]{2})\]/gi;
// 转换匹配到的16进制序列为UTF-8字符
const decodedString = str.replace(hexPattern, (match, p1) => {
// 将16进制值转换为字节
return String.fromCharCode(parseInt(p1, 16));
});
// 使用TextDecoder将字节序列转换为字符串
const bytes = [];
for (let i = 0; i < decodedString.length; i++) {
const charCode = decodedString.charCodeAt(i);
if (charCode <= 0xff) {
bytes.push(charCode);
}
}
const _str = new TextDecoder("utf-8").decode(new Uint8Array(bytes));
if (isJsonStr) {
// 尝试解析JSON字符串
try {
return JSON.parse(_str);
} catch (e) {
console.error("Error parsing JSON:", e);
return null;
}
}
return _str;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 将图片转换为 Base64 格式
# 在浏览器中使用 JavaScript
function convertToBase64() {
// 获取文件输入控件中的文件列表
var file = document.querySelector("input[type=file]").files[0];
var reader = new FileReader();
reader.onloadend = function () {
console.log("Base64 String:", reader.result);
};
// 读取文件内容,并在完成后触发`onloadend`事件
reader.readAsDataURL(file);
}
// HTML部分
// <input type="file" onchange="convertToBase64()">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 在 Node.js 中
const fs = require("fs");
// 异步读取
fs.readFile("path/to/your/image.jpg", "base64", (err, base64Image) => {
if (err) {
console.error(err);
return;
}
console.log("Base64 String:", base64Image);
});
// 同步读取
const base64Image = fs.readFileSync("path/to/your/image.jpg", "base64");
console.log("Base64 String:", base64Image);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在命令行(例如 Linux 或 macOS)中
base64 -i ./image.jpg > image_base64.txt
1