/** * ResizeObserver 会以 class 组件的形式存在, * 因为其使用 findDomNode(this) 实现 children 为 fc 时不能给 ref 的情况 * 如果 ResizeObserver 也是 fc,就没有办法在不添加额外结构的情况下拿到 dom 了 */ /* eslint-disable */ // @ts-nocheck import * as React from "react" import ResizeObserver from "resize-observer-polyfill" import findDOMNode from "rc-util/lib/Dom/findDOMNode" import toArray from "rc-util/lib/Children/toArray" import { composeRef } from "rc-util/lib/ref" import warning from "../_util/warning" interface ResizeObserverEntry { readonly borderBoxSize: ResizeObserverEntryBoxSize readonly contentBoxSize: ResizeObserverEntryBoxSize readonly contentRect: any readonly target: Element } interface ResizeObserverEntryBoxSize { blockSize: number inlineSize: number } const supportRef = (nodeOrComponent) => { if ( nodeOrComponent.type?.$$typeof && nodeOrComponent.type.$$typeof.toString().includes("forward_ref") ) { return false } // Function component node if ( nodeOrComponent.type && nodeOrComponent.type.prototype && !nodeOrComponent.type.prototype.render ) { return false } // Class component if (typeof nodeOrComponent === "function") { return false } return true } export interface IResizeObserverProps { children: React.ReactNode disabled?: boolean onResize?: (size: { width: number; height: number }) => void } interface ResizeObserverState { height: number width: number } type RefNode = React.ReactInstance | HTMLElement | null class ReactResizeObserver extends React.Component< IResizeObserverProps, ResizeObserverState > { static displayName = "ResizeObserver" resizeObserver: ResizeObserver | null = null childNode: RefNode = null currentElement: Element | null = null state = { width: 0, height: 0, } componentDidMount() { this.onComponentUpdated() } componentDidUpdate() { this.onComponentUpdated() } componentWillUnmount() { this.destroyObserver() } onComponentUpdated() { const { disabled } = this.props // Unregister if disabled if (disabled) { this.destroyObserver() return } const element = findDOMNode(this.childNode || this) as Element const elementChanged = element !== this.currentElement if (elementChanged) { this.destroyObserver() this.currentElement = element } if (!this.resizeObserver && element) { this.resizeObserver = new ResizeObserver(this.onResize) this.resizeObserver.observe(element) } } onResize = (entries: ResizeObserverEntry[]) => { const { onResize } = this.props const { width: widthState, height: heightState } = this.state const { target } = entries[0] const { width, height } = target.getBoundingClientRect() const [fixedWidth, fixedHeight] = [Math.floor(width), Math.floor(height)] if (widthState !== fixedWidth || heightState !== fixedHeight) { const size = { width: fixedWidth, height: fixedHeight } this.setState(size) if (onResize) { onResize(size) } } } setChildNode = (node: RefNode) => { this.childNode = node } destroyObserver() { if (this.resizeObserver) { this.resizeObserver.disconnect() this.resizeObserver = null } } render() { const { children } = this.props const childNodes = toArray(children) if (childNodes.length > 1) { warning( false, "ResizeObserver", "有多个 children,将只会在第一个元素上监听" ) } else if (childNodes.length === 0) { warning(false, "ResizeObserver", "没有 children") return null } const childNode = childNodes[0] if (React.isValidElement(childNode) && supportRef(childNode)) { const { ref } = childNode as any childNodes[0] = React.cloneElement(childNode as any, { ref: composeRef(ref, this.setChildNode), }) } return ( <> {childNodes.length === 1 ? childNodes[0] : childNodes.map((node, index) => { if ( !React.isValidElement(node) || ("key" in node && node.key !== null) ) { return node } return React.cloneElement(node, { key: `adui-observer-key-${index}`, }) })} ) } } export default ReactResizeObserver