javascript - 使 React 组件/div 可拖动的推荐方法

标签 javascript reactjs

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

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

谢谢。

最佳答案

我可能应该把它写成一篇博文,但这里有一个非常可靠的例子。

评论应该很好地解释了事情,但如果您有任何问题,请告诉我。

这里是 fiddle :https://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 of 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))
  }
})

关于国有制等的思考

“谁应该拥有什么国家”是一个从一开始就需要回答的重要问题。对于“可拖动”组件,我可以看到几种不同的场景。

场景一

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

场景2

父级只需要拥有“非移动位置”,因此可拖动对象将拥有它的“拖动位置”,但 onmouseup 会调用 this.props.onChange(x, y) 并将最终决定权交给父级。如果父级不喜欢可拖动对象的最终位置,它会拒绝状态更新,并且可拖动对象会“弹回到”其初始位置。

混合还是组件?

@ssorallen 指出,因为 draggable 与其说是一个事物本身,不如说是一个属性,它可能更适合作为 mixin。我对 mixin 的经验有限,所以我还没有看到它们在复杂情况下如何提供帮助或阻碍。这很可能是最佳选择。

关于javascript - 使 React 组件/div 可拖动的推荐方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20926551/

相关文章:

javascript - 是否可以从 Redux 存储中检索特定评论评论的状态

javascript - 如何打开文件对象(HTML)并在谷歌应用程序脚本中解析它

javascript - Node.js - 如何检查请求数据?

javascript - React,组件多次调用我的后端

javascript - 显示 : none is flickering content that should be hidden when loading the webpage

javascript - AngularJS 1.2.x : Change in decoding URL in routing?

javascript - jquery .on() 只工作一次

javascript - 如何在 safari 中使用 'pagehide' 事件来防止卸载?

reactjs - 不变违规 : Argument appears to not be a ReactComponent

javascript - ReactJs:如何在渲染组件时传递初始状态?