對於監聽瀏覽器的視窗大小,可以透過 window.addEventListener(‘resize’, cb) 來實現,不過有時我們會有監聽父層 div 的需求,但此時的 window 並不一定會跟著變化。近期在整合 Vue Grid 的套件的時候,遇上了此一狀況。網路上流傳著一份由 taozh1982@gmail.com 所貢獻的程式碼,藉此來運用一下。
程式碼
主要實現的原理為:在目標的 Div 中新增一個 <object> 的物件,然後監聽這個物件的 contentDocument.defaultView 的 resize 事件即可。不過在頁面切換或是該 <div> 被銷毀時,需要讓監聽器一併被 remove,以免影響效能。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by taozh on 2017/5/6. | |
* taozh1982@gmail.com | |
*/ | |
var EleResize = { | |
_handleResize: function (e) { | |
var ele = e.target || e.srcElement; | |
var trigger = ele.__resizeTrigger__; | |
if (trigger) { | |
var handlers = trigger.__z_resizeListeners; | |
if (handlers) { | |
var size = handlers.length; | |
for (var i = 0; i < size; i++) { | |
var h = handlers[i]; | |
var handler = h.handler; | |
var context = h.context; | |
handler.apply(context, [e]); | |
} | |
} | |
} | |
}, | |
_removeHandler: function (ele, handler, context) { | |
var handlers = ele.__z_resizeListeners; | |
if (handlers) { | |
var size = handlers.length; | |
for (var i = 0; i < size; i++) { | |
var h = handlers[i]; | |
if (h.handler === handler && h.context === context) { | |
handlers.splice(i, 1); | |
return; | |
} | |
} | |
} | |
}, | |
_createResizeTrigger: function (ele) { | |
var obj = document.createElement('object'); | |
obj.setAttribute('style', | |
'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;'); | |
obj.onload = EleResize._handleObjectLoad; | |
obj.type = 'text/html'; | |
ele.appendChild(obj); | |
obj.data = 'about:blank'; | |
return obj; | |
}, | |
_handleObjectLoad: function (evt) { | |
this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; | |
this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize); | |
} | |
}; | |
if (document.attachEvent) {//ie9-10 | |
EleResize.on = function (ele, handler, context) { | |
var handlers = ele.__z_resizeListeners; | |
if (!handlers) { | |
handlers = []; | |
ele.__z_resizeListeners = handlers; | |
ele.__resizeTrigger__ = ele; | |
ele.attachEvent('onresize', EleResize._handleResize); | |
} | |
handlers.push({ | |
handler: handler, | |
context: context | |
}); | |
}; | |
EleResize.off = function (ele, handler, context) { | |
var handlers = ele.__z_resizeListeners; | |
if (handlers) { | |
EleResize._removeHandler(ele, handler, context); | |
if (handlers.length === 0) { | |
ele.detachEvent('onresize', EleResize._handleResize); | |
delete ele.__z_resizeListeners; | |
} | |
} | |
} | |
} else { | |
EleResize.on = function (ele, handler, context) { | |
var handlers = ele.__z_resizeListeners; | |
if (!handlers) { | |
handlers = []; | |
ele.__z_resizeListeners = handlers; | |
if (getComputedStyle(ele, null).position === 'static') { | |
ele.style.position = 'relative'; | |
} | |
var obj = EleResize._createResizeTrigger(ele); | |
ele.__resizeTrigger__ = obj; | |
obj.__resizeElement__ = ele; | |
} | |
handlers.push({ | |
handler: handler, | |
context: context | |
}); | |
}; | |
EleResize.off = function (ele, handler, context) { | |
var handlers = ele.__z_resizeListeners; | |
if (handlers) { | |
EleResize._removeHandler(ele, handler, context); | |
if (handlers.length === 0) { | |
var trigger = ele.__resizeTrigger__; | |
if (trigger) { | |
trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize); | |
ele.removeChild(trigger); | |
delete ele.__resizeTrigger__; | |
} | |
delete ele.__z_resizeListeners; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface EleCustom { | |
__resizeTrigger__: undefined | any, | |
__z_resizeListeners: undefined | any[] | |
} | |
interface DocumentExtend { | |
attachEvent(event: string, listener: EventListener): boolean; | |
detachEvent(event: string, listener: EventListener): void; | |
} | |
const EleResize = { | |
_handleResize: function (e: Event) { | |
const ele = e.target || e.srcElement as Event & EleCustom['__resizeTrigger__'] | |
const trigger = ele?.__resizeTrigger__ | |
if (trigger) { | |
const handlers = trigger.__z_resizeListeners | |
if (handlers) { | |
const size = handlers.length | |
for (let i = 0; i < size; i++) { | |
const h = handlers[i] | |
const handler = h.handler | |
const context = h.context | |
handler.apply(context, [e]) | |
} | |
} | |
} | |
}, | |
_removeHandler: function (ele: EleCustom & HTMLElement, handler: any, context: any) { | |
const handlers = ele.__z_resizeListeners | |
if (handlers) { | |
for (let i = 0; i < handlers.length; i++) { | |
const h = handlers[i] | |
if (h.handler === handler && h.context === context) { | |
handlers.splice(i, 1) | |
return | |
} | |
} | |
} | |
}, | |
_createResizeTrigger: function (ele: EleCustom & HTMLElement) { | |
const obj = document.createElement('object') | |
obj.setAttribute('style', | |
'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;') | |
obj.onload = EleResize._handleObjectLoad | |
obj.type = 'text/html' | |
ele.appendChild(obj) | |
obj.data = 'about:blank' | |
return obj | |
}, | |
_handleObjectLoad: function () { | |
const target = this as Record<string, any> | |
target.contentDocument.defaultView.__resizeTrigger__ = target.__resizeElement__ | |
target.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize) | |
}, | |
on: undefined as unknown as Function, | |
off: undefined as unknown as Function | |
} | |
/*@ts-ignore*/ | |
if (document.attachEvent) { // ie9-10 | |
EleResize.on = function (ele: EleCustom & HTMLElement & DocumentExtend, handler: any, context: any) { | |
let handlers = ele.__z_resizeListeners | |
if (!handlers) { | |
handlers = [] | |
ele.__z_resizeListeners = handlers | |
ele.__resizeTrigger__ = ele | |
ele.attachEvent('onresize', EleResize._handleResize) | |
} | |
handlers.push({ | |
handler: handler, | |
context: context | |
}) | |
} | |
EleResize.off = function (ele: EleCustom & HTMLElement & DocumentExtend, handler: any, context: any) { | |
let handlers = ele.__z_resizeListeners | |
if (handlers) { | |
EleResize._removeHandler(ele, handler, context) | |
if (handlers.length === 0) { | |
ele.detachEvent('onresize', EleResize._handleResize) | |
delete ele.__z_resizeListeners | |
} | |
} | |
} | |
} else { | |
EleResize.on = function (ele: EleCustom & HTMLElement, handler: any, context: any) { | |
let handlers = ele.__z_resizeListeners | |
if (!handlers) { | |
handlers = [] | |
ele.__z_resizeListeners = handlers | |
if (getComputedStyle(ele, null).position === 'static') { | |
ele.style.position = 'relative' | |
}; | |
const obj = EleResize._createResizeTrigger(ele) as Record<string, any> | |
ele.__resizeTrigger__ = obj | |
obj.__resizeElement__ = ele | |
} | |
handlers.push({ | |
handler: handler, | |
context: context | |
}) | |
} | |
EleResize.off = function (ele: EleCustom & HTMLElement, handler: any, context: any) { | |
let handlers = ele.__z_resizeListeners | |
if (handlers) { | |
EleResize._removeHandler(ele, handler, context) | |
if (handlers.length === 0) { | |
const trigger = ele.__resizeTrigger__ | |
if (trigger) { | |
trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize) | |
ele.removeChild(trigger) | |
delete ele.__resizeTrigger__ | |
} | |
delete ele.__z_resizeListeners | |
} | |
} | |
} | |
} | |
export default EleResize |