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

Problems related to a resizable component

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

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

此外,我目前在该点位于右边框 5 个像素以内时显示调整大小光标,这在可调整大小 div 内时工作正常。但是,如果您从右侧接近边界(鼠标在其他 div 内),则无法 select 它,即使您在 5 像素以内。

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

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

关于如何缓解这些问题有什么建议吗?

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}

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

First off, it's awkward to drag the div element, because if the mouse enters the other element to the right while dragging, the dragging state is lost and bugs out.

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

Also, I currently show the resize cursor when the point is within 5 pixels of the right border, which works fine when inside the resizable div. However, if you approach the border from the right (mouse inside other div), you cannot select it, even though you're within 5 pixels.

我建议您为此只使用 CSS。它的用途是什么:)

Another problem is that when I drag the mouse and resize the div, the mouse selects the text it drags over.

是的,只是 CSS。一旦你的 mousedown 处理程序被执行,添加一个特殊的 CSS class 到你的元素并把这样的东西放在你的 CSS.

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

Lastly, because the element has to rerender each time it's width is changed, I've noticed that the performance is not always smooth.

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