来源于resize-observer-polyfill
1.浏览器resizeObserver兼容性存在问题
如果没有原生的ResizeObserver方法 将使用垫片提供的方法
export default (() => {// Export existing implementation if available.// 启用原生apiif (typeof global.ResizeObserver !== 'undefined') {return global.ResizeObserver;}// 启用垫片apireturn ResizeObserverPolyfill;})();
2.监听的属性变化和刷新
在树形变化后调用响应的对象 和mobx,formily类似的一套实现
// 会影响size的有 onResize只在window生效window.addEventListener('resize', this.refresh);// 普通元素怎么处理 拖拽完成形变的时候触发trannsitionend事件document.addEventListener('transitionend', this.onTransitionEnd_);// transition的形变可能影响到的属性const transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight'];// 记录和计算前后属性变化 如果变化 触发sizeChange通知function getHTMLElementContentRect(target) {const {clientWidth, clientHeight} = target;if (!clientWidth && !clientHeight) {return emptyRect;}const styles = getWindowOf(target).getComputedStyle(target);const paddings = getPaddings(styles);const horizPad = paddings.left + paddings.right;const vertPad = paddings.top + paddings.bottom;let width = toFloat(styles.width),height = toFloat(styles.height);// model is applied (except for IE).if (styles.boxSizing === 'border-box') {if (Math.round(width + horizPad) !== clientWidth) {width -= getBordersSize(styles, 'left', 'right') + horizPad;}if (Math.round(height + vertPad) !== clientHeight) {height -= getBordersSize(styles, 'top', 'bottom') + vertPad;}}if (!isDocumentElement(target)) {const vertScrollbar = Math.round(width + horizPad) - clientWidth;const horizScrollbar = Math.round(height + vertPad) - clientHeight;if (Math.abs(vertScrollbar) !== 1) {width -= vertScrollbar;}if (Math.abs(horizScrollbar) !== 1) {height -= horizScrollbar;}}return createRectInit(paddings.left, paddings.top, width, height);}
3.react-component层面组装
// 用useRef不变特性保存各阶段size数据const sizeRef = React.useRef({width: -1,height: -1,offsetWidth: -1,offsetHeight: -1,});<SingleObserver {...props} key={key}>{child}</SingleObserver>// 第一顺位获取children的ref做被监听对象的domconst elementRef = React.useRef<Element>(null);...const mergedChildren = isRenderProps ? children(elementRef) : children;// 备选通过当前reactNode的挂载找到上层domReactDom.findDOMNode(node)const currentElement: HTMLElement =findDOMNode(elementRef.current) || findDOMNode(wrapperRef.current);// 通过两层dom处理的意思是 原始组件最好自带一个wapper包裹要onResize处理的部分// 否则往顶层冒泡拿一个wapper 不一定符合// 启用监听React.useEffect(() => {const currentElement: HTMLElement =findDOMNode(elementRef.current) || findDOMNode(wrapperRef.current);if (currentElement && !disabled) {// 开启监听 回调为onInternalResizeobserve(currentElement, onInternalResize);}return () => unobserve(currentElement, onInternalResize);}, [elementRef.current, disabled]);// onInternalResizeonCollectionResize?.(sizeInfo, target, data);// defer the callback but not defer to next frame// 顺延一个frame刷新时间处理 微任务 frame开启后会查询Promise.resolve().then(() => {onResize(sizeInfo, target);});
