經(jīng)典設(shè)計(jì)模式:發(fā)布訂閱
let sub = (function () {
// 自定義事件池
let pond = {}
// 向事件池中存放方法
const on = function on(type, func) {
!pond.hasOwnProperty(type) ? pond[type] = [] : null
let arr = pond[type]
let i = 0
// 存儲(chǔ)之前實(shí)現(xiàn)去重處理
for(; i < arr.lenth; i++){
if(arr[i] === func){
return
}
}
arr.push(func)
}
// 向事件池中存放方法
const off = function on(type, func) {
let arr = pond[type] || []
let i = 0
for(; i < arr.lenth; i++){
if(arr[i] === func){
// 移除這一項(xiàng):為了不產(chǎn)生數(shù)組塌陷問(wèn)題休玩,我們不直接從原始數(shù)組中刪除娇哆,只是把當(dāng)前項(xiàng)賦值為null
arr[i] = null
return
}
}
}
// 通知事件池中的方法執(zhí)行
const fire = function on(type, ...params) {
let arr = pond[type] || []
let i = 0
for(; i < arr.lenth; i++){
if(arr[i] === null){
arr.splice(i, 1)
i--
continue
}
arr[i](...params)
}
}
return {
on,
off,
fire
}
})()
const fn1 = x => console.log('fn1', x)
const fn2 = x => console.log('fn2', x)
sub.on('LBJhui', fn1)
sub.on('LBJhui', fn1)
sub.on('LBJhui', fn2)
setTimeoouut(() => {
sub.fire('LBJhui', 100)
})
自定義DOM事件
JavaScript中的模擬事件觸發(fā):無(wú)需手動(dòng)操作,也可以基于一些代碼觸發(fā)事件「不兼容IE6-8」
- createEvent 創(chuàng)建事件對(duì)象「DOM2中事件參數(shù)是“復(fù)數(shù)”栅干,DOM3中是“單數(shù)”」
- MouseEvent
- KeyboardEvent 「DOM新增」
- Event
- ...
- initMouseEvent / initKeyboardEvent / initEvent 模式事件對(duì)象數(shù)據(jù)
- type事件類(lèi)型
- bubbles 是否冒泡傳播
- cancelable 事件是否可以取消
- dispatchEvent 手動(dòng)觸發(fā)事件
let box = document.querySelector('.box')
//DOM0 事件綁定
box.onclick = function (ev) {
console.log('DOM0 CLICK', ev)
}
//DOM2 事件綁定:事件池
box.addEventListener('click', function (ev) {
console.log('DOM2 CLICK', ev)
})
setTimeout(() => {
// box.onclick() // 缺少事件對(duì)象
// 1.創(chuàng)建事件對(duì)象
let evv = document.createEvent('MouseEvent')
ev.initMouseEvent('click', true, true)
// 2.自動(dòng)觸發(fā)事件
box.dispatchEvent(ev)
})
自定義DOM事件
- document.createEvent('CustomEvent') 或者 new CustomEvent('event_name', {'detail': xxx })
let box = document.querySelector('.box')
// 創(chuàng)建自定義事件
let ev = document.createEvent('CustomEvent')
ev.initCustomEvent('LBJhui', true, true, {
clientX: 10,
clientY: 20
})
box.addEventListener('LBJhui', ev => {
console.log(ev)
})
定時(shí)器動(dòng)畫(huà)
- setInterval / clearInterval
- setTimeout / clearTimeout
「弊端」
- 容易出現(xiàn)卡頓、抖動(dòng)的現(xiàn)象「丟幀」
- 定時(shí)器設(shè)定的等待執(zhí)行時(shí)間是不可靠的
- 不同設(shè)備的刷新頻率不一樣捐祠,我們?cè)O(shè)定的等待時(shí)間和刷新頻率不一致
擴(kuò)展:屏幕刷新頻率(圖像在屏幕上更新的速度碱鳞,也即屏幕上的圖像每秒鐘出現(xiàn)的次數(shù))
- 60赫茲(Hz):顯示器以每秒60次的頻率不斷的更新屏幕上的圖像
- 視覺(jué)停留效應(yīng):16.7ms
requestAnimationFrame / cancelAnimationFrame 「不兼容IE6-9」
- 由系統(tǒng)來(lái)決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)
- CPU節(jié)能:當(dāng)頁(yè)面被隱藏或最小化時(shí),setTimeout仍然在處理中踱蛀;requestAnimationFrame只有在頁(yè)面處于激活狀態(tài)下才會(huì)執(zhí)行
- 函數(shù)節(jié)流:回調(diào)函數(shù)在屏幕每一次的刷新間隔中只被執(zhí)行一次
- requestAnimationFrame會(huì)把每一幀中的所有DOM操作集中起來(lái)窿给,在一次重繪或回流中就完成,在隱藏或不可見(jiàn)的元素中率拒,將不會(huì)進(jìn)行重繪或回流
requestIdleCallback:在瀏覽器的空閑時(shí)間段調(diào)用的函數(shù)崩泡,這樣一些不重要的任務(wù)可以延后執(zhí)行,防止頁(yè)面卡頓
- requestIdleCallback([callback], [option -> timeout])
- 只有新版瀏覽器才支持