如何在没有 ReactDOM 的情况下检测 React 组件的溢出?

IT技术 javascript reactjs
2021-05-11 04:17:22

基本上我希望能够检测到react组件是否有溢出的子组件。就像在这个问题中一样我发现使用 ReactDOM 可以做同样的事情,但是我不能/不应该使用 ReactDOM我在建议的替代方案中没有看到任何内容ref,这是等效的。

所以我需要知道的是,在这些条件下是否有可能检测到react组件内的溢出。同样,是否有可能检测到宽度?

4个回答

除了@jered 的出色回答之外,我还想提到一个限定符,即如果 ref直接放置在 DOM element 上,则 ref 只会返回一个可以直接访问常规 DOM 元素的各种属性的元素也就是说,它不会以这种方式使用Components

所以如果你像我一样并且有以下几点:

var MyComponent = React.createClass({
  render: function(){
    return <SomeComponent id="my-component" ref={(el) => {this.element = el}}/>
  }
})

并且当您尝试访问this.element(可能在componentDidMount或 中componentDidUpdate)的DOM 属性并且您没有看到所述属性时,以下可能是适合您的替代方案

var MyComponent = React.createClass({
  render: function(){
    return <div ref={(el) => {this.element = el}}>
             <SomeComponent id="my-component"/>
          </div>
  }
})

现在您可以执行以下操作:

componentDidUpdate() {
  const element = this.element;
  // Things involving accessing DOM properties on element
  // In the case of what this question actually asks:
  const hasOverflowingChildren = element.offsetHeight < element.scrollHeight ||
                                 element.offsetWidth < element.scrollWidth;
},

@Jemar Jones 提出的解决方案的实现:

export default class OverflowText extends Component {
  constructor(props) {
    super(props);
    this.state = {
      overflowActive: false
    };
  }

  isEllipsisActive(e) {
    return e.offsetHeight < e.scrollHeight || e.offsetWidth < e.scrollWidth;
  }

  componentDidMount() {
    this.setState({ overflowActive: this.isEllipsisActive(this.span) });
  }

  render() {
    return (
      <div
        style={{
          width: "145px",
          textOverflow: "ellipsis",
          whiteSpace: "nowrap",
          overflow: "hidden"
        }}
        ref={ref => (this.span = ref)}
      >
        <div>{"Triggered: " + this.state.overflowActive}</div>
        <span>This is a long text that activates ellipsis</span>
      </div>
    );
  }
}

编辑 1o0k7vr1m3

是的,您可以使用ref.

ref在官方文档中阅读更多关于工作原理的信息:https : //facebook.github.io/react/docs/refs-and-the-dom.html

基本上,ref只是在组件第一次呈现时运行的回调,紧接在componentDidMount调用之前回调中的参数是调用该ref函数的 DOM 元素所以如果你有这样的事情:

var MyComponent = React.createClass({
  render: function(){
    return <div id="my-component" ref={(el) => {this.domElement = el}}>Hello World</div>
  }
})

MyComponent坐骑,它会调用该ref函数集this.domElement的DOM元素#my-component

有了这个,使用类似的东西getBoundingClientRect()在渲染后测量你的 DOM 元素并确定子元素是否溢出父元素是相当容易的:

https://jsbin.com/lexonoyamu/edit?js,console,output

请记住,渲染DOM 元素之前无法测量它们的大小/溢出,因为根据定义,它们还不存在。在将其渲染到屏幕之前,您无法测量某物的宽度/高度。

使用 React 钩子也可以实现相同的效果:

您需要的第一件事是保存文本 openoverflow active 的布尔值的状态

const [textOpen, setTextOpen] = useState(false);
const [overflowActive, setOverflowActive] = useState(false);

接下来,您需要对要检查是否溢出的元素进行引用:

const textRef = useRef();
<p ref={textRef}>
    Some huuuuge text
</p>

接下来是一个检查元素是否溢出的函数:

function isOverflowActive(event) {
    return event.offsetHeight < event.scrollHeight || e.offsetWidth < e.scrollWidth;
}

然后你需要一个 useEffect 钩子来检查上面的函数是否存在溢出:

useEffect(() => {
    if (isOverflowActive(reviewTextRef.current)) {
        setOverflowActive(true);
        return;
    }

    setOverflowActive(false);
}, [isOverflowActive]);

现在有了这两个状态和一个检查溢出元素是否存在的函数,你可以有条件地渲染一些元素(例如显示更多按钮):

{!textOpen && !overflowActive ? null : (
    <button>{textOpen ? 'Show less' : 'Show more'}</button>
)}