Javascript
获取给定月份的具体天数
function getMonthEndDay(year: number, month: number): number {
return 32 - new Date(year, month - 1, 32).getDate();
}
getMonthEndDay(2012, 10)
// means 2012/10 has 31 days
移除重复字符
// ES6
// from https://stackoverflow.com/questions/35609731/remove-duplicate-in-a-string-javascript
function removeDuplicate (s) {
return Array.from(new Set(s.split(''))).join('')
}
// use map
function removeDuplicate (s) {
var arr = s.split('')
var map = {}
var len = arr.length
for (let i = 0; i < len; i++) {
if (!map.hasOwnProperty(arr[i])) map[arr[i]] = true
}
return Object.keys(map).join('');
}
removeDuplicate('你好你哈') // 你好哈
removeDuplicate('76jkkjs98d7') // 76jks98d
Related:
Audio
对象播放音频
通过 function playAudio () {
const instance = new Audio()
instance.crossOrigin = '*'
// when its ready it will auto play
instance.oncanplaythrough = () => {
instance.play()
}
instance.onended = () => {
instance.pause()
}
// get duration time
instance.onloadedmetadata = () => {
const duration = (instance.duration).toFixed(0)
}
instance.src = src // your audio src
instance.load()
}
Related:
存储单位转换 KB MB GB
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
Related:
指定日期倒计时
function countDown () {
var deadline = 1898098000 // give a unix timestamp
var now = new Date().getTime()
var result = ''
setInterval(() => {
var t = deadline - now
var days = Math.floor(t / (1000 * 60 * 60 * 24))
var hours = Math.floor((t % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
var minutes = Math.floor((t % (1000 * 60 * 60)) / (1000 * 60))
var seconds = Math.floor((t % (1000 * 60)) / 1000)
if (t < 0) {
// clearInterval()
days = 0
hours = 0
minutes = 0
seconds = 0
}
result = days + 'days' + hours + 'h' + minutes + 'm' + seconds + 's'
}, 1000)
千位分隔符
function seperate (num) {
const reg = /(?!^)(?=(\d{3})+$)/g
return String(num).replace(reg, ',');
}
seperate(111111) // 111,111
人民币 分->元 转换
// 分 -> 元
function regFenToYuan(fen, flag = true) {
var num = fen
num = fen * 0.01
num += ''
var reg = num.indexOf('.') > -1 ? /(\d{1,3})(?=(?:\d{3})+\.)/g : /(\d{1,3})(?=(?:\d{3})+$)/g
num = num.replace(reg, '$1')
num = toDecimal2(num, flag)
return num
}
// 保留两位小数 equal toFixed(2)
function toDecimal2(x, flag = true) {
var ff = parseFloat(x)
if (isNaN(ff)) {
return false
}
var f = Math.round(x * 100) / 100
var s = f.toString()
var rs = s.indexOf('.')
if (rs < 0) {
rs = s.length
if (flag) {
s += '.'
}
}
if (flag) {
while (s.length <= rs + 2) {
s += '0'
}
}
return s
}
regFenToYuan(134) // 1.34
regFenToYuan(1434) // 14.34
数字变动动画效果
/**
* quickly change number from A to B
* @param from number
* @param to number
*/
function animNumber(from, to) {
const start = new Date().getTime()
const loop = () => {
setTimeout(() => {
const now = (new Date().getTime()) - start
const progress = now / 700
const result = to > from ? Math.floor((to - from) * progress + from) : Math.floor(from - (from - to) * progress)
const res = progress < 1 ? result : to
if (res) {
// update number
console.log(res)
}
if (progress < 1) loop()
}, 90)
}
loop()
}
格式化 年月日 时分秒
const date = new Date(time);
const year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
// let hours = date.getHours();
// let minutes = date.getMinutes();
// let seconds = date.getSeconds();
month = month < 10 ? `0${month}` : month;
day = day < 10 ? `0${day}` : day;
// hours = hours < 10 ? `0${hours}` : hours;
// minutes = minutes < 10 ? `0${minutes}` : minutes;
// seconds = seconds < 10 ? `0${seconds}` : seconds;
16 进制颜色转变成 rgb 颜色
function hexToRgb (hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: null;
};
rgb 颜色转变成16 进制颜色
function rgbToHex(r, g, b) {
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
邮箱脱敏
function desensitize (email: string) {
const part = email.split('@');
const prefix = part[0];
const domain = '@' + part[1];
return (
prefix.charAt(0) + '******' + prefix.charAt(prefix.length - 1) + domain
);
};
图片尺寸缩放
function resize (width: number, height: number) => {
let ratio = 0;
// change _width _height to your size
const _width = 1280;
const _height = 1920;
if (width > _width) {
ratio = width / _width;
const scaleHeight = height / ratio;
return { width: _width, height: Math.round(scaleHeight) };
} else if (height > _height) {
ratio = height / _height;
const scaleWidth = width / ratio;
return { width: Math.round(scaleWidth), height: _height };
}
return { width, height };
};
xx天前
function formatDate = (input) => {
const date = (input instanceof Date) ? input : new Date(input);
const formatter = new Intl.RelativeTimeFormat('zh');
const ranges = {
years: 3600 * 24 * 365,
months: 3600 * 24 * 30,
weeks: 3600 * 24 * 7,
days: 3600 * 24,
hours: 3600,
minutes: 60,
seconds: 1
};
const secondsElapsed = (date.getTime() - Date.now()) / 1000;
for (let key in ranges) {
if (ranges[key] < Math.abs(secondsElapsed)) {
const delta = secondsElapsed / ranges[key];
return formatter.format(Math.round(delta), key);
}
}
}
关键字高亮
function highLight(str, keywords) {
var re = new RegExp(keywords.join("|"),"gi");
var res = str.replace(re, function(matched){
return '<mark>' + matched + '</mark>';
});
return res;
}
const res = highLight('我是导演,我不比烂', ['我', '导'])
IOS 下 微信返回触发刷新页面
let isPageHide = false;
window.addEventListener('pageshow', function () {
if (isPageHide) {
window.location.reload();
}
});
window.addEventListener('pagehide', function () {
isPageHide = true;
});
简单 JS 正则替换 Markdown 语法为 HTML 标签
function parse(markdownText) {
const htmlText = markdownText
.replace(/\*\*([^*><]+)\*\*/gim, '<strong>$1</strong>')
.replace(/\*([^*><]+)\*/gim, '<em>$1</em>')
return htmlText.trim()
}
var str = '我是**加粗**,我是*倾斜*,好巧,我也是*倾斜*'
console.log(parse(str));
过滤注释字符串
const trimComment = function (str) {
return str.replace(/\/\/[\w\W]+?(?:\n|$)/g, '').replace(/\/\*[\w\W]+?\*\//gm, '');
}
光标位于富文本编辑框的最后
<div id="input" contenteditable="true">我是内容内容<div>
此时执行 input.focus() 的方法,光标是在文字的最前面的,实现当输入框聚焦的时候,光标在文字的最后。
input.focus()
// 创建range
const range = window.getSelection();
// range 选择obj下所有子内容
range.selectAllChildren(input);
//光标移至最后
range.collapseToEnd();
or
const selection = document.getSelection();
const range = document.createRange();
range.setStartAfter(input.lastChild)
selection.removeAllRanges();
selection.addRange(range);
input.focus()
拖拽释放时候内容类型的判断
cantainer.addEventListener("dragover", function(event) {
event.preventDefault();
});
cantainer.addEventListener('drop', function (event) {
console.log(event.dataTransfer.items[0].type.startsWith('image'));
event.preventDefault();
});
鼠标左右按键判断
use auxclick event
已知页面中有个按钮如下:
<button><h1>点击我!</h1></button>
请实现,鼠标左键点击此按钮,按钮背景色随机,右键或中键点击此按钮,按钮文字颜色随机,同时,不显示上下文菜单。
注:无需考虑 IE 浏览器,已经暗示了考点是某个 IE 不支持的点击事件类型了。
全组合算法
/*
全组合算法
input [a,b,c,d,e]
output [Array(5), Array(10), Array(10), Array(5), Array(1)]
flatten output,
['A', 'B', 'C', 'D', 'E']
['AB', 'AC', 'BC', 'AD', 'BD', 'CD', 'AE', 'BE', 'CE', 'DE']
['ABC', 'ABD', 'ACD', 'BCD', 'ABE', 'ACE', 'BCE', 'ADE', 'BDE', 'CDE']
['ABCD', 'ABCE', 'ABDE', 'ACDE', 'BCDE']
['ABCDE']
*/
const combination = (arr) => {
const list = [];
for (let i = 0; i < arr.length; i++) {
list.push([]);
}
const l = Math.pow(2, arr.length) - 1;
for (let i = 1; i <= l; i++) {
const t = [];
for (let s = i, k = 0; s > 0; s >>= 1, k++) {
if ((s & 1) === 1) {
t.push(arr[k]);
}
}
list[t.length - 1].push([t]); // join 的分隔符可以自行约定
}
return list.flat(2); // flatten
};
固定版本号大小比较
const checkVersion = (a: string, b: string) => {
return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }); // 0:= 1:a>b -1:b>a
}
JS 读取本地图片
const readURL = (file) => {
return new Promise((res, rej) => {
const reader = new FileReader();
reader.onload = e => res(e.target.result);
reader.onerror = e => rej(e);
reader.readAsDataURL(file);
});
};
JS 伪随机获取闭区间内的一个随机数
function generateRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
简单双休日判断
function isWeekday(timestamp) {
const day = new Date(timestamp).getDay()
return day % 6 !== 0
}
数组反转-不更改原数组
Array.prototype.toReverse = function () {
return this.slice(0).reverse()
}
异常图片的点击重载
页面中有不少<img src="?.jpg">
元素,由于网络等原因,这些图片可能加载失败。 请实现,如果图片加载失败,点击这些图片触发图片重载,如果图片加载正常,不做任何处理。
img.addEventListener('click', function(){
this.decode().catch(err => {
this.src= this.src + '?t='+Date.now()
})
})
// 更好
document.addEventListener('click', function (event) {
var ele = event.target;
if (ele.nodeName == 'IMG' && !ele.naturalWidth) {
ele.src = ele.src;
}
});
媒体查询 - 浏览器窗口宽度实时监听
const mql = window.matchMedia('(max-width: 640px)');
let isMobile = mql.matches;;
mql.onchange = () => {
isMobile = mql.matches;
}
DOM Node 节点的位置互换
function swspNode(A,B){
if (A.contains(B) || B.contains(A)) {
console.error('不能替换相互包含的节点')
return
}
const temp = new Text('')
A.after(temp)
B.after(A)
temp.after(B)
temp.remove()
}
判断浏览器是否支持 Background Fetch API
if ("BackgroundFetchManager" in self) {
console.log("支持")
}
判断一个页面处于focus状态
document.hasFocus()
搜索内容的高亮匹配
const highLight = function (str, arr) {
arr.forEach(key => {
str = str.replaceAll(key, `<mark>${key}</mark>`);
});
return str;
}
判断浏览器是否支持 avif 图像格式
https://github.com/Kagami/avif.js/blob/master/avif.js
// Decode AVIF data using native browser's AV1 decoder.
function hasAv1Support() {
const vid = document.createElement("video");
return vid.canPlayType('video/mp4; codecs="av01.0.05M.08"') === "probably";
}
非合法JSON字符串转成对象
let str = '{ opacity: 0.5, color: "black", mode: "hide" }';
new Function('return ' + str)()
判断当前浏览器的默认滚动条是否占据宽度
// 页面高度不足,无法准确验证
window.innerWidth - document.body.clientWidth
function getScrollbarWidth() {
// 新建一个带有滚动条的DIV元素,再计算该元素offsetWidth和clientWidth的差值。
var scrollDiv = document.createElement("div");
scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
document.body.appendChild(scrollDiv);
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
return scrollbarWidth;
};
Web组件是否定义(customElements.define('xx-xx'))的判断
drop.matches(':defined')
两侧容器同步滚动
移除 DOM 上的事件
let clone = element.cloneNode(true);
element.after(clone);
element.remove();
for (let key in clone) {
if (/^on/.test(key) && typeof clone[key] == 'function') {
clone[key] = null;
}
}
校验一个文件是否为 UTF8 格式
const isUTF8 = (bytes: Uint8Array) => {
let i = 0
while (i < bytes.length) {
if (
// ASCII
bytes[i] == 0x09 ||
bytes[i] == 0x0a ||
bytes[i] == 0x0d ||
(0x20 <= bytes[i] && bytes[i] <= 0x7e)
) {
i += 1
continue
}
if (
// non-overlong 2-byte
0xc2 <= bytes[i] &&
bytes[i] <= 0xdf &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf
) {
i += 2
continue
}
if (
// excluding overlongs
(bytes[i] == 0xe0 &&
0xa0 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf) || // straight 3-byte
(((0xe1 <= bytes[i] && bytes[i] <= 0xec) || bytes[i] == 0xee || bytes[i] == 0xef) &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf) || // excluding surrogates
(bytes[i] == 0xed && 0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x9f && 0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xbf)
) {
i += 3
continue
}
if (
// planes 1-3
(bytes[i] == 0xf0 &&
0x90 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf &&
0x80 <= bytes[i + 3] &&
bytes[i + 3] <= 0xbf) || // planes 4-15
(0xf1 <= bytes[i] &&
bytes[i] <= 0xf3 &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0xbf &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf &&
0x80 <= bytes[i + 3] &&
bytes[i + 3] <= 0xbf) || // plane 16
(bytes[i] == 0xf4 &&
0x80 <= bytes[i + 1] &&
bytes[i + 1] <= 0x8f &&
0x80 <= bytes[i + 2] &&
bytes[i + 2] <= 0xbf &&
0x80 <= bytes[i + 3] &&
bytes[i + 3] <= 0xbf)
) {
i += 4
continue
}
return false
}
return true
}
const fileIsUTF8 = (file: RcFile): Promise<boolean> => {
return new Promise((resolve) => {
const reader = new FileReader()
reader.addEventListener('loadend', (e: ProgressEvent<FileReader>) => {
const data = e.target?.result as ArrayBuffer
const uint8Array = new Uint8Array(data)
const flag = isUTF8(uint8Array)
return resolve(flag)
})
reader.readAsArrayBuffer(file)
})
}