如何可靠地测量React组件以计算弹出框和标注的位置?

时间:2016-12-02 18:53:37

标签: javascript reactjs dom react-bootstrap

我正在使用react和react-bootstrap。我想知道是否有比我提出的更好,更清洁,更惯用的方法。

问题

我想定位一个弹出标注,指向我页面上的一个按钮,提示用户应该在哪里开始工作流程。用户随后可以解除此弹出窗口。我花了很长时间才弄清楚测量元素的尺寸和位置以正确定位标注的黑客方法:

标注的目标:

<Button 
  bsClass="button" 
  className="button-blue" 
  id="connectParentsButton"
  onClick={( event ) => { this.handleOpenInviteParents( event );}}
  ref={( input ) => { this.connectParentsButtonRef = input; }}
>
  + Connect Parents
</Button> 

我们的想法是使用ref将目标存储为父React组件的属性,然后从兄弟标注组件访问它以执行测量。

标注组件:

<RightBottomHintBox 
  isShow={this.state.isShowConnectParentsHint && !this.state.isDismissHideConnectParentsHint} 
  target={this.connectParentsButtonRef} 
  id="connectParentsHint" 
  onHide={this.handleHideConnectParentsHint}
/>

在我的RightBottomHintBox组件中,我必须

  • 使用document.getElementById()获取维度和位置
  • 使用防护来避免尝试访问尚不存在的节点
  • 在类属性中存储维度和坐标,而不是组件状态

我必须在callout的render()中执行此操作,以确保我的callout组件即使未显示也会挂载,以便DOM节点存在且可以正确测量。

let myStyle = this.props.isShow ? {} : { visibility: 'hidden' };

方法失败

  • 在标注componentDidMount()触发时计算尺寸。标注或目标的DOM节点通常不存在

  • 在父组件的componentDidMount()触发时计算维度。存在同样的问题,您无法确定此时是否存在DOM节点。

以上两种方法引领我进入这个主题:When exactly is `componentDidMount` fired?

一篇文章建议,为了确保所有DOM节点都准备就绪,您必须转到顶部组件。我不喜欢这种方法,因为它会打破封装和关注点的分离。

另一个帖子How can I respond to the width of an auto-sized DOM element in React?建议使用react-measure库进行测量,这可能有效,但对于我的特定情况,我想避免让另一个库来管理,因为这个应用很小。

背景背景

我正在创建一个页面,允许用户输入学生父母的电子邮件地址列表。初始页面列出了已输入的学生和家长的电子邮件地址。但是,当用户第一次访问此页面时,可能会有一个学生列表,没有父电子邮件地址。我想向用户提供一个提示,他们应该点击“Connect Parents”按钮打开一个向导来引导用户输入数据。

1 个答案:

答案 0 :(得分:0)

我有另一次失败的尝试here可能会刺激某人找到正确的解决方案。

export function getSize(cpt) {
    var elem = document.getElementById("ruler");    
    const html = ReactDOMServer.renderToStaticMarkup(cpt);
    elem.innerHTML = html;
    return [elem.scrollWidth, elem.scrollHeight];
}

var Foo = React.createClass({
  componentDidMount() {
    const sz = this.elem.getBoundingClientRect();
    ReactDOM.render(<span>{ [sz.width,sz.height].join("x") }</span>,
                    document.getElementById('actual'));
  },
  render() {
    return <div ref={e => { this.elem = e; }} className="content">
             <p> Bar!! BAZ </p> <p> another line </p> </div>;
  }
})

将getSize设置为渲染到任何div(屏幕上或关闭)会产生大约76x84,而componentDidMount报告的实际大小(并由dev工具确认)为188x52。