与可调整大小的组件相关的问题

时间:2015-05-15 19:56:38

标签: reactjs

我正在编写一个组件,如果单击其右边框并拖动它,则允许更改它的子元素的宽度。

但是我遇到了一些问题。首先,拖动div元素很尴尬,因为如果鼠标在拖动时进入右边的另一个元素,拖动状态就会丢失并出现错误。

另外,当点在右边框的5个像素内时,我当前显示调整大小光标,在可调整大小的div内部工作正常。但是,如果您从右侧接近边框(鼠标位于其他div内),即使您在5个像素内,也无法选择它。

另一个问题是,当我拖动鼠标并调整div的大小时,鼠标会选择拖动它的文本。

最后,因为元素每次更改时都必须重新渲染,所以我注意到性能并不总是很平滑。

有关如何缓解这些问题的建议吗?

Resizable = React.createClass({

  propTypes: {
    id       : React.PropTypes.string,
    class    : React.PropTypes.string,
    width    : React.PropTypes.number,
    onResize : React.PropTypes.func,
    onAction : React.PropTypes.func,
  },

  getInitialState: function() {
    return {
      showResizeCursor : false,
      canResize        : false,
    };
  },

  getDefaultProps: function() {
    return {
    };
  },

  _handleMouseMove: function(event) {
    var node       = React.findDOMNode(this);
    var offsets    = node.getBoundingClientRect();
    var divLeft    = offsets.left;
    var divRight   = offsets.right;
    var mouseX     = event.clientX;

    var maxWidth = this.props.maxWidth || this.props.width;
    var minWidth = this.props.minWidth || this.props.width;
    var newWidth = mouseX - divLeft + 200;
    var isWithinBounds = newWidth <= maxWidth && newWidth >= minWidth;

    if (this.state.canResize && isWithinBounds) {
      this.props.onResize(newWidth);
    }

    var difference = Math.abs(divRight - mouseX);

    if (difference < 4) {
      return this.setState({ showResizeCursor: true });
    }

    if (this.state.showResizeCursor) {
      this.setState({ showResizeCursor: false });
    }
  },

  _handleMouseUp: function() {
    this.setState({ canResize: false });
  },

  _handleMouseDown: function() {
    if (this.state.showResizeCursor) {
      this.setState({ canResize: true });
    }
  },

  render: function() {
    var style = {
      width : this.state.width,
    };

    if (this.state.showResizeCursor) { style.cursor = 'col-resize'; }

    return (
      <div id={this.props.id}
        style       ={style}
        className   ={this.props.class}
        onMouseDown ={this._handleMouseDown}
        onMouseUp   ={this._handleMouseUp}
        onMouseMove ={this._handleMouseMove}
        onMouseLeave={this._handleMouseUp}


      >
        {this.props.children}
      </div>
    );
  }
});

使用示例:

render: function() {
...
return (
  <Wrapper>
    <Resizable
      id       = {'list-view'}
      width    = {this.state.listViewWidth}
      maxWidth = {this.state.listViewMaxWidth}
      minWidth = {this.state.listViewMinWidth}
      onResize = {this._handleListViewResize}
    >
      {first_column_that_should_be_resizable}
    </Resizable>
    {second_column_not_resizeable}

1 个答案:

答案 0 :(得分:6)

这里有许多不同的问题......

  

首先,拖动div元素很尴尬,因为如果鼠标在拖动时进入右边的另一个元素,拖动状态就会丢失并且会出错。

当您开始编写第一个拖放行为时,这是一个非常常见的问题。你不应该在同一个元素上监听mousedown,mousemove和mouseup事件,你应该只监听mousedown事件,并且在那个处理程序中开始监听另外两个但是在文档的主体上。这样,您就拥有了一个全局处理程序,鼠标不会遇到其他元素的问题。

  

另外,当点在右边框的5个像素内时,我当前显示调整大小光标,在可调整大小的div内部工作正常。但是,如果您从右侧接近边框(鼠标在其他div内),即使您在5像素范围内,也无法选择它。

我建议你只使用CSS。它是什么:)

  

另一个问题是,当我拖动鼠标并调整div的大小时,鼠标会选择拖动它的文本。

是的,只是CSS。执行mousedown处理程序后,为元素添加一个特殊的CSS类,并在CSS中添加类似的内容。

.disable-select {
  -webkit-user-select: none;  
  -moz-user-select: none;    
  -ms-user-select: none;      
  user-select: none;
}
  

最后,因为每次更改宽度时元素必须重新渲染,我注意到性能并不总是平滑。

我不认为React是你最好的选择。我只想使用jQuery和componentDidMount等生命周期方法添加此行为。这样,您可以使用普通的jQuery(在每次鼠标移动时)调整div的大小,然后将最终状态(即最终大小)应用于mouseup处理程序上的组件。