個人筆記(部分來源於網絡),持續更新中…
文章目錄
防抖
const debounce = (func, delay, immediate) => {
return function () {
clearTimeout(func.timer);
const _this = this;
if (immediate) {
func.apply(_this, arguments);
return;
}
func.timer = setTimeout(() => func.apply(_this, arguments), delay);
}
};
節流
const throttle = (func, delay) => {
let timer, last;
return function () {
const _this = this;
const _args = arguments;
const now = +new Date();
if (last && now < last + delay) {
clearTimeout(timer);
timer = setTimeout(() => {
last = now;
func.apply(_this, _args);
}, delay);
} else {
last = now;
func.apply(this, _args);
}
}
};
獲取字符串中的數字
let str = '123abc!@#456';
str = Number(str.replace(/[^0-9]/ig, '')); // 123456
計算兩個時間相差的時間間隔
/**
* 計算兩個時間戳相差的時間間隔(最大單位爲分鐘,即兩個時間戳相差的時間使用 分鐘和秒 來表示)
* @param {number|string} s start
* @param {number|string} e end
*/
function __getOrderEffctiveTime(s, e) {
if (typeof s !== 'number') s = new Date(s).getTime();
if (typeof e !== 'number') e = new Date(e).getTime();
const diff = e - s,
dayTimer = 24*3600*1000,
hourTimer = 3600*1000,
minuteTimer = 60*1000;
const day = Math.floor(diff / dayTimer);
const outDay = diff % dayTimer;
const hour = Math.floor(outDay / hourTimer);
const outHour = outDay % hourTimer;
const minute = Math.floor(outHour / minuteTimer);
const outMinute = outHour % minuteTimer;
const second = Math.floor(outMinute / 1000);
let tempMin = 0;
if (day > 0) { tempMin = day * 24 * 60; }
if (hour > 0) { tempMin += hour * 60; }
if (minute > 0) { tempMin += minute; }
return {
minute: tempMin,
second,
};
}
console.log(__getOrderEffctiveTime('2020.06.17', '2020.06.18')); // { minute: 1440, second: 0 }
console.log(__getOrderEffctiveTime('2020.06.17 12:00', '2020.06.18 02:00')); // { minute: 840, second: 0 }
console.log(__getOrderEffctiveTime('2020.06.17 12:00:30', '2020.06.18 02:00')); // { minute: 839, second: 30 }
// 當然也可以計算時間戳
時間格式化(時間戳)
// t爲時間戳
function __dateFormater(formater, t) {
let date = t ? new Date(t) : new Date(),
Y = date.getFullYear() + '',
M = date.getMonth() + 1,
D = date.getDate(),
H = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds();
return formater.replace(/YYYY|yyyy/g,Y)
.replace(/YY|yy/g, Y.substr(2,2))
.replace(/MM/g, (M<10?'0':'') + M)
.replace(/DD/g, (D<10?'0':'') + D)
.replace(/HH|hh/g, (H<10?'0':'') + H)
.replace(/mm/g, (m<10?'0':'') + m)
.replace(/ss/g, (s<10?'0':'') + s);
}
// dateFormater('YYYY-MM-DD HH:mm', t) ==> 2019-06-26 18:30
// dateFormater('YYYYMMDDHHmm', t) ==> 201906261830
時間格式化(將指定字符串由一種時間格式轉化爲另一種)
// fmtOriginal: 日期的原始格式 fmtFinally: 日期轉換後的格式
function __dateFmt(str, fmtOriginal, fmtFinally) {
// '19491001' 'YYYYMMDD' 'YYYY年MM月DD日'
str += '';
let Y = '';
if (~(Y = fmtOriginal.indexOf('YYYY'))) {
Y= str.substr(Y, 4);
fmtFinally= fmtFinally.replace(/YYYY|yyyy/g,Y);
} else if (~(Y = fmtOriginal.indexOf('YY'))) {
Y = str.substr(Y, 2);
fmtFinally= fmtFinally.replace(/YY|yy/g, Y);
}
let k,i
['M','D','H','h','m','s'].forEach(s => {
i = fmtOriginal.indexOf(s+s);
k = ~i ? str.substr(i, 2) : '';
fmtFinally= fmtFinally.replace(s+s, k);
})
return fmtFinally;
}
// dateFmt('19491001', 'YYYYMMDD', 'YYYY年MM月DD日') ==> 1949年10月01日
// dateFmt('111119491001', '----YYYYMMDD', 'YYYY年MM月DD日') ==> 1949年10月01日
// dateFmt('1949年10月01日', 'YYYY年MM月DD日', 'YYYYMMDD') ==> 19491001
// 一般的也可以用正則來實現
// '1949年10月01日'.replace(/(\d{4})年(\d{2})月(\d{2})日/, '$1-$2-$3') ==> 1949-10-01
格式化金額(添加千位符)
// __isNaN 方法參考本文章
function __handleAmount(num) {
if (String(num).indexOf(',') !== -1) return num; // 已經格式化
if (__isNaN(num)) return Number(num); // NaN
num = parseFloat(num).toFixed(2).toString().split('.');
num[0] = num[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,');
return num.join('.');
}
獲取 url 中的參數
function __getUrlParam(url) {
let arrObj = url.split("?");
let params = Object.create(null)
if (arrObj.length > 1) {
arrObj = arrObj[1].split('&');
arrObj.forEach(item => {
item = item.split('=');
params[item[0]] = item[1];
})
}
return params;
}
let url = document.location.toString();
getUrlParam(url); // ?a=1&b=2&c=3 ==> {a: "1", b: "2", c: "3"}
判斷是否是 Number
原生的 isNaN 有個怪異行爲,如果 isNaN 函數的參數不是 Number 類型, isNaN 函數會首先嚐試將這個參數轉換爲數值,然後纔會對轉換後的結果是否是 NaN 進行判斷。因此,對於能被強制轉換爲有效的非 NaN 數值來說(空字符串和布爾值分別會被強制轉換爲數值 0 和 1),會返回 false 值。
具體請參考:MDN: isNaN()
function __isNaN(v) {
return !(typeof v === 'string' || typeof v === 'number') || isNaN(v)
}
獲取數組中非 NaN 的最大值和最小值
Math.max() 會返回給定的一組數字中的最大值,但如果給定的參數中至少有一個參數無法被轉換成數字,則會返回 NaN。
// 最大值
function __getMax(arr) {
arr = arr.filter(item => !_isNaN(item));
return arr.length ? Math.max.apply(null, arr) : undefined;
}
// __getMax([1, 2, '11', null, 'fdf', []]) ==> 11
// 最小值
function __getMin(arr) {
arr = arr.filter(item => !_isNaN(item));
return arr.length ? Math.min.apply(null, arr) : undefined;
}
// min([1, 2, '11', null, 'fdf', []]) ==> 1
獲取兩個數值間的隨機數
// 兩個值不分大小先後
function __random(lower, upper) {
lower = +lower || 0;
upper = +upper || 0;
return Math.random() * (upper - lower) + lower;
}
// random(0, 0.5) ==> 0.3567039135734613
// random(2, 1) ===> 1.6718418553475423
// random(-2, -1) ==> -1.4474325452361945
性能分析
window.onload = function() {
setTimeout(function() {
let t = performance.timing, report = new Object(), rt = report.timer = new Object(), rm = report.memory = new Object();
rt.dns = { name: 'DNS查詢耗時', v: (t.domainLookupEnd - t.domainLookupStart).toFixed(0) };
rt.tcp = { name: 'TCP鏈接耗時', v: (t.connectEnd - t.connectStart).toFixed(0) };
rt.request = { name: 'request請求耗時', v: (t.responseEnd - t.responseStart).toFixed(0) };
rt.dom = { name: '解析dom樹耗時', v: (t.domComplete - t.domInteractive).toFixed(0) };
rt.whiteScreen = { name: '白屏時間', v: (t.responseStart - t.navigationStart).toFixed(0) };
rt.domReady = { name: 'domready時間', v: (t.domContentLoadedEventEnd - t.navigationStart).toFixed(0) };
rt.onload = { name: 'onload時間', v: (t.loadEventEnd - t.navigationStart).toFixed(0) };
if (t = performance.memory) {
rm.jsPercent = (t.usedJSHeapSize / t.totalJSHeapSize * 100).toFixed(2) + '%';
}
console.log('performance report: ',report);
}, 0);
}
禁止某些鍵盤事件
document.addEventListener('keydown', function(event) {
return !(
112 == event.keyCode || //F1
123 == event.keyCode || //F12
event.ctrlKey && 82 == event.keyCode || //ctrl + R
event.ctrlKey && 78 == event.keyCode || //ctrl + N
event.shiftKey && 121 == event.keyCode || //shift + F10
event.altKey && 115 == event.keyCode || //alt + F4
"A" == event.srcElement.tagName && event.shiftKey //shift + 點擊a標籤
) || (event.returnValue = false);
});
禁止右鍵、選擇、複製
['contextmenu', 'selectstart', 'copy'].forEach(function(ev) {
document.addEventListener(ev, function(event) {
return event.returnValue = false;
})
});
全屏 / 退出全屏
// 全屏
function __toFullScreen() {
let elem = document.body;
elem.webkitRequestFullScreen
? elem.webkitRequestFullScreen()
: elem.mozRequestFullScreen
? elem.mozRequestFullScreen()
: elem.msRequestFullscreen
? elem.msRequestFullscreen()
: elem.requestFullScreen
? elem.requestFullScreen()
: console.error('瀏覽器不支持全屏');
}
// 退出全屏
function __exitFullscreen(){
let elem = parent.document;
elem.webkitCancelFullScreen
? elem.webkitCancelFullScreen()
: elem.mozCancelFullScreen
? elem.mozCancelFullScreen()
: elem.cancelFullScreen
? elem.cancelFullScreen()
: elem.msExitFullscreen
? elem.msExitFullscreen()
: elem.exitFullscreen
? elem.exitFullscreen()
: console.error('瀏覽器不支持');
}