React:渲染后无法获得正确的元素宽度

时间:2015-06-22 11:32:18

标签: javascript iframe width reactjs

如果一段文本大于其容器,我试图在React中设置Marquee,但即使在组件渲染后我也无法获得正确的容器宽度。

我在另一个答案React “after render” code?中读到你必须使用我正在尝试的requestAnimationFrame并且它仍然无效。

如果我记录容器的宽度,则显示宽度为147px,使用样式表中的min-width设置,但正确的宽度应为320px,当屏幕最小宽度为600px时,使用媒体查询设置该宽度。

这是一个子组件,如果父组件有任何差异且iFrame的宽度超过600px,则父组件将在iFrame中呈现。

JS:

module.exports = React.createClass({

  componentDidUpdate: function () {
    // Setup marquee
    this.initMarquee();
  },

  render: function () {
    // Setup marquee
    this.initMarquee();

    var artistName = this.props.artist.artistName;
    var trackName  = this.props.track.trackName;

    return (
      <div className="MV-player-trackData no-select" ref="mvpTrackData">
        <div className="MV-player-trackData-marquee-wrap" ref="mvpMarqueeWrap">
          <div className="MV-player-trackData-marquee" ref="mvpMarquee">
            <a className="MV-player-trackData-link no-select" href={this.props.storeUrl} target="_blank">
              <span id="mvArtistName">{artistName}</span> &ndash; <span id="mvTrackName">{trackName}</span>
            </a>
          </div>
        </div>
      </div>
    )
  },

  initMarquee: function () {
    if ( typeof requestAnimationFrame !== 'undefined' ) {
      //store a this ref, and
      var self = this;
      //wait for a paint to setup marquee
      window.requestAnimationFrame(function() {
        self.marquee();
      });
    }
    else {
      // Suport older browsers
      window.setTimeout(this.marquee, 2000);
    }
  },

  marquee: function () {
    var marquee     = React.findDOMNode(this.refs.mvpMarquee);
    var marqueeWrap = React.findDOMNode(this.refs.mvpMarqueeWrap);

    // If the marquee is greater than its container then animate it
    if ( marquee.clientWidth > marqueeWrap.clientWidth ) {
      marquee.className += ' is-animated';
    }
    else {
      marquee.className = marquee.className.replace('is-animated', '');
    }
  }

});

CSS:

.MV-player-trackData-marquee-wrap {
  height: 20px;
  line-height: 20px;
  min-width: 147px;
  overflow: hidden;
  position: relative;
  width: 100%;

  @media only screen and (min-width : 600px) {
    min-width: 320px;
  }
}

我尝试了许多不同的解决方案,包括laidoutreact-component-width-mixin,但它们都不起作用。我试过反应组件宽度mixin,因为在我的应用程序的另一部分我尝试获取window.innerWidth的值,但在渲染后也返回0,除非我设置超时约2秒,不幸的是有时候由于数据加载和其他回调,2秒还不够长,因此可以轻松制动。

非常感谢任何帮助。感谢。

更新 其中一个答案正确地指出我应该在我this.initMarquee();内调用componentDidMount,不幸的是我在测试时粘贴了错误的代码,看看它是否在内部调用{{1} 1}}。正确的代码如下所示:

render

不幸的是,这也不起作用,我仍然收到marqueeWrap的错误宽度。

更新:2015年6月24日 只是为了澄清,这是我试图实现的marquee effect,只有当文本比容器更大时才会实现,因为当它不大时,它会毫无意义地滚动它。

此处还有来自React团队的Github Issue链接,说明了React在浏览器绘制之前呈现的原因。 - 所以在这种情况下,我想知道如何可靠地获得有问题元素的宽度。

4 个答案:

答案 0 :(得分:3)

可能出现的一个问题是,当componentDidMount触发时,您的CSS尚未加载。这可能发生在webpack中,包括你的包中也包含你的js的css,即使你已经在项目中的组件之前包含了css。

答案 1 :(得分:1)

正如您已经指出的,在处理虚拟DOM时有几个问题。你绝对不想尝试使用jQuery来操纵DOM节点,而且React可能会因你的尝试而尖叫。

有一个名为React-Context的图书馆可以完全按照您的要求行事。您可以将其api公开给您的包装器组件,然后能够侦听虚拟dom中组件上的事件。

这个库有点尘土飞扬,但它应该与您共享的代码示例一起使用。

答案 2 :(得分:0)

我对这个问题感到困惑,你想用宽度做什么?

除此之外,React只是JavaScript,因此您应该能够在componentDidMount函数上触发一​​些代码,该函数在元素在浏览器dom中具有物理空间之后执行。因此,就像任何JavaScript代码一样,您将能够访问该div并获得它的宽度等......

JavaScript方式......

document.getElementById("mydiv").offsetWidth;

jQuery方式......

$('#mydiv').width();

如果您要解决的问题是动态更改div的宽度,因为它在渲染后看起来不正确......这应该是使用CSS完成的。

答案 3 :(得分:0)

您不应该在render()方法中调用this.initMarquee();

通常,您不应在render()方法中使用DOM。

尝试使用this.initMarquee();方法调用componentDidMount

(我真的不明白在这种情况下使用requestAnimationFrame