小编典典

推荐的使React组件/ div可拖动的方式

reactjs

我想制作一个可拖动(即可以通过鼠标重定位)的React组件,该组件似乎必然涉及全局状态和分散的事件处理程序。我可以在JS文件中使用一个全局变量来以肮脏的方式进行操作,甚至可以将其包装在一个不错的闭包接口中,但是我想知道是否有一种方法可以更好地与React结合。

另外,由于我以前从未在原始JavaScript中做到过这一点,所以我想看看专家是如何做到的,以确保我处理了所有极端情况,尤其是与React相关的情况。

谢谢。


阅读 815

收藏
2020-07-22

共1个答案

小编典典

我可能应该把它变成一篇博客文章,但这是一个很可靠的例子。

这些评论应该可以很好地说明问题,但是如果您有任何疑问,请告诉我。

这是玩的小提琴:http :
//jsfiddle.net/Af9Jt/2/

var Draggable = React.createClass({
  getDefaultProps: function () {
    return {
      // allow the initial position to be passed in as a prop
      initialPos: {x: 0, y: 0}
    }
  },
  getInitialState: function () {
    return {
      pos: this.props.initialPos,
      dragging: false,
      rel: null // position relative to the cursor
    }
  },
  // we could get away with not having this (and just having the listeners on
  // our div), but then the experience would be possibly be janky. If there's
  // anything w/ a higher z-index that gets in the way, then you're toast,
  // etc.
  componentDidUpdate: function (props, state) {
    if (this.state.dragging && !state.dragging) {
      document.addEventListener('mousemove', this.onMouseMove)
      document.addEventListener('mouseup', this.onMouseUp)
    } else if (!this.state.dragging && state.dragging) {
      document.removeEventListener('mousemove', this.onMouseMove)
      document.removeEventListener('mouseup', this.onMouseUp)
    }
  },

  // calculate relative position to the mouse and set dragging=true
  onMouseDown: function (e) {
    // only left mouse button
    if (e.button !== 0) return
    var pos = $(this.getDOMNode()).offset()
    this.setState({
      dragging: true,
      rel: {
        x: e.pageX - pos.left,
        y: e.pageY - pos.top
      }
    })
    e.stopPropagation()
    e.preventDefault()
  },
  onMouseUp: function (e) {
    this.setState({dragging: false})
    e.stopPropagation()
    e.preventDefault()
  },
  onMouseMove: function (e) {
    if (!this.state.dragging) return
    this.setState({
      pos: {
        x: e.pageX - this.state.rel.x,
        y: e.pageY - this.state.rel.y
      }
    })
    e.stopPropagation()
    e.preventDefault()
  },
  render: function () {
    // transferPropsTo will merge style & other props passed into our
    // component to also be on the child DIV.
    return this.transferPropsTo(React.DOM.div({
      onMouseDown: this.onMouseDown,
      style: {
        left: this.state.pos.x + 'px',
        top: this.state.pos.y + 'px'
      }
    }, this.props.children))
  }
})

关于国家所有权等的思考

从一开始,“谁应该拥有什么状态”是一个重要的问题。在“可拖动”组件的情况下,我可以看到几种不同的情况。

场景1

父级应拥有可拖动对象的当前位置。在这种情况下,可拖动对象仍将拥有“我正在拖动”状态,但是this.props.onChange(x, y)每当发生mousemove事件时都会调用它。

方案2

父级只需要拥有“固定位置”,因此可拖动对象将拥有其“拖动位置”,但是在onmouseup上它将调用this.props.onChange(x, y)并将最终决定推迟到父级。如果父级不喜欢可拖动对象的最终位置,它将不会更新其状态,并且可拖动对象会“快照”回到其初始位置,然后再进行拖动。

混合蛋白或成分?

@ssorallen指出,因为“可拖动”与其说是事物本身,不如说是一个属性,它可能更好地用作混合。我对mixins的经验有限,所以我还没有看到它们在复杂情况下如何提供帮助或妨碍。这可能是最好的选择。

2020-07-22