docs: 添加文章内容(2013 ~ 2023)
This commit is contained in:
681
docs/content/collection-javascript-code.md
Normal file
681
docs/content/collection-javascript-code.md
Normal file
@@ -0,0 +1,681 @@
|
||||
---
|
||||
title: 「合集」常用的 JavaScript 代码
|
||||
date: 2025-03-16T22:02:06Z
|
||||
lastmod: 2025-03-16T22:02:51Z
|
||||
tags: [合集,代码片段,Web 前端,JavaScript]
|
||||
---
|
||||
|
||||
# 「合集」常用的 JavaScript 代码
|
||||
|
||||
## document
|
||||
|
||||
#### 焦点不在当前窗口时改变标题
|
||||
|
||||
```javascript
|
||||
document.addEventListener('visibilitychange', function () {
|
||||
if (document.hidden) {
|
||||
document.title = '焦点不在当前窗口';
|
||||
} else {
|
||||
document.title = '焦点在当前窗口';
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 解除离开页面检测
|
||||
|
||||
```javascript
|
||||
document.hasFocus = function () {
|
||||
return true;
|
||||
};
|
||||
```
|
||||
|
||||
#### 使网页内容(body)可编辑
|
||||
|
||||
**开启**
|
||||
|
||||
```javascript
|
||||
document.body.contentEditable = 'true';
|
||||
document.designMode = 'on';
|
||||
```
|
||||
|
||||
```javascript
|
||||
(function () {
|
||||
let items = document.querySelectorAll('iframe');
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
items[i].contentDocument.body.contentEditable = 'true';
|
||||
items[i].contentDocument.designMode = 'on';
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
**关闭**
|
||||
|
||||
```javascript
|
||||
document.body.contentEditable = 'false';
|
||||
document.designMode = 'off';
|
||||
```
|
||||
|
||||
```javascript
|
||||
(function () {
|
||||
let items = document.querySelectorAll('iframe');
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
items[i].contentDocument.body.contentEditable = 'false';
|
||||
items[i].contentDocument.designMode = 'off';
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## function
|
||||
|
||||
#### 查找元素的 Vue 对象
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @typedef {object} FunctionResult
|
||||
* @property {boolean} state 是否查找成功
|
||||
* @property {HTMLElement} element Vue 对象所在的元素
|
||||
* @property {object} data 找到的 Vue 对象
|
||||
* @property {object[]} parents 父 Vue 对象
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 查找元素的 Vue 对象
|
||||
* @param {HTMLElement} el 需要查找的元素
|
||||
* @returns {FunctionResult} 返回查找结果信息
|
||||
*/
|
||||
function findElementVue(el) {
|
||||
|
||||
/** @type {FunctionResult} */
|
||||
const result = {
|
||||
state: false,
|
||||
element: null,
|
||||
data: null,
|
||||
parents: [],
|
||||
};
|
||||
|
||||
const attrName = '__vue__';
|
||||
|
||||
// 查找属性
|
||||
while (el) {
|
||||
const data = el[attrName];
|
||||
if (data) {
|
||||
result.state = true;
|
||||
result.element = el;
|
||||
result.data = data;
|
||||
break;
|
||||
} else {
|
||||
el = el.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
// 查找父对象
|
||||
if (result.state) {
|
||||
let attrName = '$parent';
|
||||
let parent = result.data[attrName];
|
||||
|
||||
while (parent) {
|
||||
result.parents.push(parent);
|
||||
parent = parent[attrName];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 查找字符 `char` 在 `str` 中第 `num` 次出现的位置
|
||||
|
||||
```javascript
|
||||
function findChar(str = '', char = '', num = 1) {
|
||||
var index = str.indexOf(char);
|
||||
num = num - 1;
|
||||
if (num > 0) {
|
||||
for (var i = 0; i < num; i++) {
|
||||
index = str.indexOf(char, index + 1);
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
```
|
||||
|
||||
#### 格式化时间
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 格式化时间
|
||||
* @param {(number|string|Date)} [time] 要格式化的时间(默认当前)
|
||||
* @param {string} [format] 需要的格式(默认 yyyy-mm-dd hh:ii:ss)
|
||||
* @returns {string} 格式化后的时间
|
||||
*/
|
||||
function formatTime(time = new Date(), format = 'yyyy-mm-dd hh:ii:ss') {
|
||||
|
||||
let timeType = typeof time;
|
||||
|
||||
/** @type {Date} */
|
||||
let dateObj = null;
|
||||
|
||||
if (timeType == 'number' || timeType == 'string') {
|
||||
dateObj = new Date(time);
|
||||
} else if (timeType == 'object') {
|
||||
dateObj = time;
|
||||
}
|
||||
|
||||
// 时间信息
|
||||
let timeInfo = {
|
||||
// 年月日
|
||||
y: dateObj.getFullYear(),
|
||||
m: dateObj.getMonth() + 1,
|
||||
d: dateObj.getDate(),
|
||||
// 时分秒
|
||||
h: dateObj.getHours(),
|
||||
i: dateObj.getMinutes(),
|
||||
s: dateObj.getSeconds(),
|
||||
};
|
||||
|
||||
// 格式占位符正则
|
||||
let formatReg = {
|
||||
y: /y+/g,
|
||||
m: /m+/g,
|
||||
d: /d+/g,
|
||||
h: /h+/g,
|
||||
i: /i+/g,
|
||||
s: /s+/g,
|
||||
};
|
||||
|
||||
for (let key in formatReg) {
|
||||
|
||||
// 正则匹配
|
||||
let matched = format.match(formatReg[key]);
|
||||
|
||||
// 获取对应的时间
|
||||
let timeValue = String(timeInfo[key]);
|
||||
|
||||
// 无匹配结果
|
||||
if (!matched) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 根据匹配结果(位数)进行替换
|
||||
matched.forEach(function (v) {
|
||||
let tLength = timeValue.length;
|
||||
let vLength = v.length;
|
||||
// 长度不足,补零
|
||||
if (tLength < vLength) {
|
||||
timeValue = timeValue.padStart(v.length, '0');
|
||||
}
|
||||
// 长度超出,截取
|
||||
// if (tLength > vLength) {
|
||||
// timeValue = timeValue.substring(tLength - vLength);
|
||||
// }
|
||||
// 替换对应的值
|
||||
format = format.replace(v, timeValue);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return format;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取随机的十六进制色
|
||||
|
||||
```javascript
|
||||
/** 获取随机的十六进制色 */
|
||||
function getHEXColor() {
|
||||
var codes = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
];
|
||||
var colors = ['#'];
|
||||
for (let i = 0; i < 6; i++) {
|
||||
let index = Math.floor(Math.random() * 16);
|
||||
colors.push(codes[index]);
|
||||
}
|
||||
return colors.join('');
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取元素的边界信息
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 获取元素的边界信息(当前元素必须在父元素内)
|
||||
* @param {Element} curr 当前 DOM 元素
|
||||
* @param {Element} parent 父 DOM 元素
|
||||
*/
|
||||
function getBoundaryInfo(curr, parent) {
|
||||
|
||||
if (!curr || !parent) {
|
||||
console.error('获取失败,缺少参数!');
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = {};
|
||||
var currRect = curr.getBoundingClientRect();
|
||||
var parentRect = parent.getBoundingClientRect();
|
||||
|
||||
// 当前元素四角坐标和宽高
|
||||
result.curr = {
|
||||
x0: currRect.left,
|
||||
x1: currRect.right,
|
||||
y0: currRect.top,
|
||||
y1: currRect.bottom,
|
||||
w: currRect.width,
|
||||
h: currRect.height,
|
||||
};
|
||||
|
||||
// 父元素四角坐标
|
||||
result.parent = {
|
||||
x0: parentRect.left,
|
||||
x1: parentRect.right,
|
||||
y0: parentRect.top,
|
||||
y1: parentRect.bottom,
|
||||
w: parentRect.width,
|
||||
h: parentRect.height,
|
||||
};
|
||||
|
||||
// 距离
|
||||
result.distance = {
|
||||
top: result.curr.y0 - result.parent.y0,
|
||||
bottom: result.parent.y1 - result.curr.y1,
|
||||
left: result.curr.x0 - result.parent.x0,
|
||||
right: result.parent.x1 - result.curr.x1,
|
||||
};
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取元素的坐标信息
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 获取元素的坐标信息(四个角以及宽高)
|
||||
* @param {Element} element DOM 元素
|
||||
*/
|
||||
function getElemPosInfo(element) {
|
||||
if (!element) {
|
||||
console.error('获取失败,缺少参数!');
|
||||
return null;
|
||||
}
|
||||
let rect = element.getBoundingClientRect();
|
||||
let data = {
|
||||
x0: rect.left,
|
||||
x1: rect.right,
|
||||
y0: rect.top,
|
||||
y1: rect.bottom,
|
||||
w: rect.width,
|
||||
h: rect.height,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取月份第一天和最后一天的时间戳
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 获取月份第一天和最后一天的时间戳
|
||||
* @param {number} year 年份
|
||||
* @param {number} month 月份
|
||||
* @returns `{ start: 第一天, end: 最后一天 }`
|
||||
*/
|
||||
function getTimestampOfMonth(year, month) {
|
||||
var start = new Date(year, month - 1, 1)
|
||||
var end = new Date(year, month, 0);
|
||||
var time = {
|
||||
start: start.getTime(),
|
||||
end: end.getTime()
|
||||
};
|
||||
return time;
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取坐标下方的元素
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 获取坐标下方的元素(从子元素到父元素)
|
||||
* @param {number} x 横坐标
|
||||
* @param {number} y 纵坐标
|
||||
*/
|
||||
function elemsFromPoint(x, y) {
|
||||
|
||||
if (x === undefined || y === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
||||
x = Math.floor(x);
|
||||
y = Math.floor(y);
|
||||
|
||||
let item = document.elementFromPoint(x, y);
|
||||
let items = [];
|
||||
|
||||
if (item) {
|
||||
items.push(item);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
while (item.parentElement) {
|
||||
item = item.parentElement;
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
#### 计算字符串的字符数
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 计算字符串的字符数(数字英文字母 +1,其他 +3)
|
||||
* @param {string} str 被检测的字符串
|
||||
* @returns {number} 字符数
|
||||
*/
|
||||
function calcChars(str) {
|
||||
var reg = /[0-9a-zA-Z]/;
|
||||
var sum = 0;
|
||||
for (let i in str) {
|
||||
if (reg.test(str.charAt(i))) {
|
||||
sum += 1;
|
||||
} else {
|
||||
sum += 3;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
```
|
||||
|
||||
#### 加减法精度
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 加减法精度
|
||||
* @param {string} type 类型(plus、sub)
|
||||
* @param {number} [num1] 数值1,默认为 0
|
||||
* @param {number} [num2] 数值2,默认为 0
|
||||
* @returns {(number|null)} 返回两个数值相加或相减后的结果
|
||||
*/
|
||||
function accPlusAndSub(type, num1 = 0, num2 = 0) {
|
||||
|
||||
var decimalsNum1 = (String(num1).split('.')[1] || '').length;
|
||||
var decimalsNum2 = (String(num2).split('.')[1] || '').length;
|
||||
var decimalsMax = Math.max(decimalsNum1, decimalsNum2);
|
||||
var multiplies = Math.pow(10, decimalsMax);
|
||||
|
||||
if (type === 'plus') {
|
||||
return ((num1 * multiplies + num2 * multiplies) / multiplies);
|
||||
} else if (type === 'sub') {
|
||||
return ((num1 * multiplies - num2 * multiplies) / multiplies);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 检测用户是否离开页面
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 检测用户是否离开页面(一秒检测一次)
|
||||
* @param {object} [options] 配置选项
|
||||
* @param {function} [options.onblur] 用户离开页面时的回调函数
|
||||
* @param {function} [options.onfocus] 用户返回页面时的回调函数
|
||||
* @param {string} [options.blurDelay] 设定用户离开页面多久后才调用 onblur
|
||||
* - 单位为秒
|
||||
* - 默认 0
|
||||
* @param {string} [options.timerName] 定时器名称
|
||||
* - 用于 setInterval()
|
||||
* - 默认 tCheckPageBlur
|
||||
*/
|
||||
function checkPageBlur(options) {
|
||||
|
||||
var config = {
|
||||
onblur: null,
|
||||
onfocus: null,
|
||||
blurDelay: 0,
|
||||
timerName: 'tCheckPageBlur',
|
||||
};
|
||||
|
||||
Object.assign(config, options);
|
||||
|
||||
var timerName = config.timerName; // 定时器名称
|
||||
var checkDelay = 0; // 延时
|
||||
var blurTriggered = false; // 标记状态
|
||||
|
||||
clearInterval(window[timerName]);
|
||||
window[timerName] = setInterval(function () {
|
||||
var isFocus = document.hasFocus();
|
||||
|
||||
if (isFocus && blurTriggered) {
|
||||
// 在页面且触发过 blur
|
||||
blurTriggered = false;
|
||||
checkDelay = 0;
|
||||
try {
|
||||
config.onfocus && (config.onfocus());
|
||||
} catch (err) {
|
||||
console.error('[检测] 回调函数 onfocus 出错\n', err);
|
||||
}
|
||||
} else if (!isFocus && !blurTriggered) {
|
||||
// 不在页面且未触发 blur
|
||||
if (checkDelay >= config.blurDelay) {
|
||||
blurTriggered = true;
|
||||
checkDelay = 0;
|
||||
try {
|
||||
config.onblur && (config.onblur());
|
||||
} catch (err) {
|
||||
console.error('[检测] 回调函数 onblur 出错\n', err);
|
||||
}
|
||||
} else {
|
||||
checkDelay += 1;
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
|
||||
// 调用
|
||||
checkPageBlur({
|
||||
onblur: function () {
|
||||
console.log('[检测] 用户离开页面');
|
||||
},
|
||||
onfocus: function () {
|
||||
console.log('[检测] 用户返回页面');
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### 解析 URL 地址的参数(?=...)为一个对象
|
||||
|
||||
```javascript
|
||||
function queriesToObj(url = '') {
|
||||
var split = url.split('?')[1];
|
||||
var arr = split.split('&');
|
||||
var obj = {};
|
||||
|
||||
arr.forEach(function (item) {
|
||||
var kv = item.split('=');
|
||||
obj[kv[0]] = kv[1];
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
```
|
||||
|
||||
#### 矩形碰撞检测
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 矩形碰撞检测
|
||||
* @param {Element} elemA 当前元素
|
||||
* @param {Element} elemB 目标元素
|
||||
* @param {boolean} [checkAside] 是否包含边缘碰撞,默认包含
|
||||
* @returns {object} `{ error: 是否检测失败, hit: 是否碰撞 }`
|
||||
*/
|
||||
function rectColisionCheck(elemA, elemB, checkAside = true) {
|
||||
const result = {
|
||||
error: false,
|
||||
hit: false,
|
||||
};
|
||||
|
||||
if (!(elemA && elemB)) {
|
||||
console.error('缺少参数');
|
||||
result.error = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
const rectA = elemA.getBoundingClientRect();
|
||||
const rectB = elemB.getBoundingClientRect();
|
||||
|
||||
if (checkAside) {
|
||||
result.hit = !(
|
||||
rectA.bottom < rectB.top ||
|
||||
rectA.left > rectB.right ||
|
||||
rectA.top > rectB.bottom ||
|
||||
rectA.right < rectB.left
|
||||
);
|
||||
} else {
|
||||
result.hit = !(
|
||||
rectA.bottom <= rectB.top ||
|
||||
rectA.left >= rectB.right ||
|
||||
rectA.top >= rectB.bottom ||
|
||||
rectA.right <= rectB.left
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
#### 设置事件对象属性
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 设置事件对象属性
|
||||
* @param {Eveny} ev 事件对象
|
||||
* @param {object} props 要设置的属性
|
||||
*/
|
||||
function setEvProps(ev, props = {}) {
|
||||
if (ev) {
|
||||
for (let key in props) {
|
||||
Object.defineProperty(ev, key, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return props[key];
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 通过点路径访问对象属性
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 通过点路径访问对象属性
|
||||
* @param {object} obj
|
||||
* @param {string} path
|
||||
*/
|
||||
function getObjValue(obj, path = '') {
|
||||
|
||||
if (typeof obj !== 'object') {
|
||||
console.error('访问失败,参数 obj 错误!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof path !== 'string') {
|
||||
console.error('访问失败,参数 path 错误!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (path === '') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
return path.split('.').reduce((a, b) => {
|
||||
return (a === undefined ? a : a[b]);
|
||||
}, obj);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 暂停执行代码一段时间
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 暂停执行代码一段时间
|
||||
* @param {number} [time] 时长(毫秒),默认 1000
|
||||
* @returns {Promise} Promise
|
||||
*/
|
||||
function sleep(time = 1000) {
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
|
||||
await sleep(1000);
|
||||
```
|
||||
|
||||
#### 字符串转文件
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @description 字符串转文件
|
||||
* @param {string} data 字符串数据
|
||||
* @param {string} filename 文件名
|
||||
* @param {string} filetype 文件类型(MIME)
|
||||
*/
|
||||
function strToFile(data = '', filename = 'export.txt', filetype = 'text/plain') {
|
||||
|
||||
// 转为 Blob
|
||||
var strToBlob = new Blob([data], { type: filetype });
|
||||
// URL 对象兼容性处理
|
||||
var urlObject = window.URL || window.webkitURL || window;
|
||||
// 创建对象 URL
|
||||
var blobURL = urlObject.createObjectURL(strToBlob);
|
||||
// 创建 a 元素
|
||||
var aElem = document.createElement('a');
|
||||
|
||||
// 设置属性
|
||||
aElem.classList.add('hidden');
|
||||
aElem.download = filename;
|
||||
aElem.href = blobURL;
|
||||
aElem.target = '_blank';
|
||||
|
||||
// 添加元素
|
||||
document.body.appendChild(aElem);
|
||||
|
||||
// 模拟点击
|
||||
aElem.click();
|
||||
|
||||
// 移除元素
|
||||
aElem.remove();
|
||||
|
||||
// 释放对象
|
||||
urlObject.revokeObjectURL(blobURL);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user