inula/packages/inula-dev-tools/src/components/resizeEvent.ts

96 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
*
* 由于 ResizeObserver 对 IE 和低版本主流浏览器不兼容,需要自己实现一套兼容方案
* 这是一个不依赖任何框架的监听 dom 元素尺寸变化的解决方案
* 浏览器出于性能考虑,只有 window 的 resize 事件会触发,我们通过 object 标签可以得到
* 一个 window 对象,让 object dom 元素成为待观测 dom 的子元素,并且和待观测 dom 大小一致。
* 这样一旦待观测 dom 的大小发生变化window 的大小也会发生变化,我们就可以通过监听 window
* 大小变化的方式监听待观测 dom 的大小变化
*
* <div id='test>
* <object> --> 和父 div 保持大小一致
* <html></html> --> 添加 resize 事件监听
* </object>
* </div>
*
*/
function timeout(func) {
return setTimeout(func, 20);
}
function requestFrame(func) {
const raf = requestAnimationFrame || timeout;
return raf(func);
}
function cancelFrame(id) {
const cancel = cancelAnimationFrame || clearTimeout;
cancel(id);
}
// 在闲置帧触发回调事件,如果在本次触发前存在未处理回调事件,需要取消未处理回调事件
function resizeListener(event) {
const win = event.target;
if (win.__resizeRAF__) {
cancelFrame(win.__resizeRAF__);
}
win.__resizeRAF__ = requestFrame(function () {
const observeElement = win.__observeElement__;
observeElement.__resizeCallbacks__.forEach(function (func) {
func.call(observeElement, observeElement, event);
});
});
}
function loadObserver(this: any) {
// 将待观测元素传递给 object 标签的 window 对象,这样在触发 resize 事件时可以拿到待观测元素
this.contentDocument.defaultView.__observeElement__ = this.__observeElement__;
// 给 html 的 window 对象添加 resize 事件
this.contentDocument.defaultView.addEventListener('resize', resizeListener);
}
export function addResizeListener(element: any, func: any) {
if (!element.__resizeCallbacks__) {
element.__resizeCallbacks__ = [func];
element.style.position = 'relative';
const observer = document.createElement('object');
observer.setAttribute(
'style',
'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'
);
observer.data = 'about:blank';
observer.onload = loadObserver;
observer.type = 'text/html';
observer['__observeElement__'] = element;
element.__observer__ = observer;
element.appendChild(observer);
} else {
element.__resizeCallbacks__.push(func);
}
}
export function removeResizeListener(element, func) {
element.__resizeCallbacks__.splice(element.__resizeCallbacks__.indexOf(func), 1);
if (!element.__resizeCallbacks__.length) {
element.__observer__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
element.removeChild(element.__observer__);
element.__observer__ = null;
}
}