赞
踩
通过addEventListener添加事件监听窗口的resize事件,触发相应函数从而获取目标元素大小。
//index.less .box{ width:100%; height:50%; display:flex; padding:20px flex-direction: column; .resizebox{ width:100%; flex:1; } } //index.js const MyApp = ()=>{ const resizeRef = useRef<HTMLDivElement>(null); const resizeChange = () => { let width= resizeRef. current.offsetWidth let height=resizeRef .current.offsetHeight; console.log(width,height,"======") }; useEffect(() => { // 监听 window.addEventListener('resize', resizeChange); // 销毁 return () => window.removeEventListener('resize', resizeChange); }, []); return ( <div className="box"> <div className="resizebox" ref={ resizeRef }></div> </div> ) }
通过构造一个 ResizeObserver 对象(全局的一个api)以观察者模式监听任意 Element / SvgElement 的尺寸变化。
//index.js const MyApp = ()=>{ const resizeRef = useRef<HTMLDivElement>(null); const resizeChange = (entry) => { const {width,height} =entry.contentRect let width= resizeRef. current.offsetWidth let height=resizeRef .current.offsetHeight; console.log(width,height,"======") }; useEffect(() => { const resizeObserver = new ResizeObserver((entries) => { if (!Array.isArray(entries) || !entries.length) { return; } for (let entry of entries) { resizeChange (entry)); } } }); resizeObserver.observe(resizeRef. current) //一定要卸载,不卸载这个,组件销毁后会一直找这个dom元素,会假死也不报错! return (): void => { resizeObserver.unobserve(resizeRef. current) }; }, []); return ( <div className="box"> <div className="resizebox" ref={ resizeRef }></div> </div> ) }
这样写很麻烦,而且resizeObserver是一个全局的,这里卸载的话,如果其他地方用到就也失效了,应该将不需要监听的元素从resizeObserver的队列中去除,所以为了方便可以全局封装一个resizeObserver,如下:
const _global = window as any; type ResizeConfig = [Element, ((...args: any) => void)[]]; function createResizeObserver(dom: Element, resizeFn: (...args: any) => void) { if (!window.ResizeObserver) { return {}; } let resizeObserver: ResizeObserver; let resizeObserverConfig: ResizeConfig[]; let isObserver = false; if (_global._RESIZE_OBSERVER_CONFIG) { resizeObserverConfig = _global._RESIZE_OBSERVER_CONFIG as ResizeConfig[]; const index = resizeObserverConfig.findIndex((v) => v[0] === dom); if (index > -1) { isObserver = true; resizeObserverConfig[index][1].push(resizeFn); } else { resizeObserverConfig.push([dom, [resizeFn]]); } } else { resizeObserverConfig = []; resizeObserverConfig.push([dom, [resizeFn]]); } _global._RESIZE_OBSERVER_CONFIG = resizeObserverConfig; if (_global._RESIZE_OBSERVER) { resizeObserver = _global._RESIZE_OBSERVER; } else { resizeObserver = new ResizeObserver((entries) => { if (!Array.isArray(entries) || !entries.length) { return; } for (let entry of entries) { const resizeItem = resizeObserverConfig.find((v) => v[0] === entry.target); const resizeHandles = resizeItem ? resizeItem[1] : undefined; if (resizeHandles) { resizeHandles.forEach((handle) => handle(entry)); } } }); } _global._RESIZE_OBSERVER = resizeObserver; if (!isObserver) { resizeObserver.observe(dom); } return resizeObserver; } function unResizeObserver(dom: Element, handle: (...args: any) => void) { if (!window.ResizeObserver) { return; } let resizeObserverConfig: ResizeConfig[]; let resizeObserver: ResizeObserver; if (_global._RESIZE_OBSERVER_CONFIG) { resizeObserverConfig = _global._RESIZE_OBSERVER_CONFIG; } if (_global._RESIZE_OBSERVER) { resizeObserver = _global._RESIZE_OBSERVER; } if (resizeObserver && resizeObserverConfig) { if (handle) { const index = resizeObserverConfig.findIndex((v) => v[0] === dom); resizeObserverConfig[index][1] = resizeObserverConfig[index][1].filter((v) => v !== handle); if (resizeObserverConfig[index][1].length === 0) { resizeObserver.unobserve(dom); resizeObserverConfig = resizeObserverConfig.filter((v) => v[0] !== dom); } } else { resizeObserverConfig = resizeObserverConfig.filter((v) => v[0] !== dom); resizeObserver.unobserve(dom); } _global._RESIZE_OBSERVER_CONFIG = resizeObserverConfig; } } const resizeObserver = { createResizeObserver, unResizeObserver, }; export default resizeObserver;
使用:
const MyApp = ()=>{ const resizeRef = useRef<HTMLDivElement>(null); const resizeChange = (entry) => { const {width,height} =entry.contentRect let width= resizeRef. current.offsetWidth let height=resizeRef .current.offsetHeight; console.log(width,height,"======") }; useLayoutEffect(() => { resizeObserver.createResizeObserver(containerRef.current as HTMLElement, resizeChange ) return () => resizeObserver.unResizeObserver(containerRef.current as HTMLElement, resizeChange ) }, [resizeChange ]); return ( <div className="box"> <div className="resizebox" ref={ resizeRef }></div> </div> ) }
封装函数
class ResizeHelper { ele: HTMLDivElement; resizeObject: HTMLObjectElement; resizeWindow: Window; constructor(ele: HTMLDivElement) { this.ele = ele; this.ele.style.position = 'relative'; this.resizeObject = this.createObject(); this.resizeWindow = this.resizeObject.contentDocument.defaultView; } createObject() { 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.type = 'text/html'; obj.data = 'about:blank'; this.ele.appendChild(obj); return obj; } onResize(fn: (...args: any) => void) { this.resizeWindow.addEventListener('resize', fn); } offResize(fn: (...args: any) => void) { try { this.resizeWindow.removeEventListener('resize', fn); } catch (e) { console.warn(e); } } dispose() { try { this.resizeObject.remove(); this.resizeWindow = null; this.ele = null; this.resizeObject = null; } catch (e) { console.warn(e); } } } export default ResizeHelper;
使用 :
//index.js const MyApp = ()=>{ const resizeRef = useRef<HTMLDivElement>(null); const resizeChange = (e: any) => { let width= resizeRef. current.offsetWidth let height=resizeRef .current.offsetHeight; console.log(width,height,"======") }; useEffect(() => { const resizedom = new ResizeHelper (resizeRef ) // 监听 resizedom .onResize('resize', resizeChange); // 销毁 return () => resizedom.dispose(); }, []); return ( <div className="box"> <div className="resizebox" ref={ resizeRef }></div> </div> ) }
监听 DOM 节点尺寸变化的 Hook。
//index.js
const MyApp = ()=>{
const resizeRef = useRef<HTMLDivElement>(null);
const size = useSize(ref);
console.log(size?.width, size?.height,"=====")
}, [size ]);
return (
<div className="box">
<div className="resizebox" ref={ resizeRef }></div>
</div>
)
}
源码其实用的是resize-observer-polyfill中封装好的resizeObserver
import ResizeObserver from 'resize-observer-polyfill';
const resizeObserver = new ResizeObserver((entries) => {
entries.forEach((entry) => {
const { clientWidth, clientHeight } = entry.target;
setState({
width: clientWidth,
height: clientHeight,
});
});
});
resizeObserver.observe(el);
return () => {
resizeObserver.disconnect();
};
resize-observer-polyfill的源码解析可以去看一下这几篇文章,大概看了一下和2方法中封装的resizeObserver差不多的原理。
https://blog.csdn.net/qq_38377521/article/details/115311799
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。