使 React 组件/div 可拖动的推荐方法 [英] Recommended way of making React component/div draggable

查看:29
本文介绍了使 React 组件/div 可拖动的推荐方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to make a draggable (that is, repositionable by mouse) React component, which seems to necessarily involve global state and scattered event handlers. I can do it the dirty way, with a global variable in my JS file, and could probably even wrap it in a nice closure interface, but I want to know if there's a way that meshes with React better.

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

Also, since I've never done this in raw JavaScript before, I'd like to see how an expert does it, to make sure I've got all the corner cases handled, especially as they relate to React.

谢谢.

推荐答案

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

I should probably turn this into a blog post, but here's pretty solid example.

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

The comments should explain things pretty well, but let me know if you have questions.

这里是小提琴: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))
  }
})

关于国有制等的思考

谁应该拥有什么状态"从一开始就是一个需要回答的重要问题.对于可拖动"组件,我可以看到一些不同的场景.

Thoughts on state ownership, etc.

"Who should own what state" is an important question to answer, right from the start. In the case of a "draggable" component, I could see a few different scenarios.

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

the parent should own the current position of the draggable. In this case, the draggable would still own the "am I dragging" state, but would call this.props.onChange(x, y) whenever a mousemove event occurs.

父级只需要拥有非移动位置",因此可拖动对象将拥有它的拖动位置",但 onmouseup 它将调用 this.props.onChange(x, y)并将最终决定推迟给父母.如果父级不喜欢可拖动对象的最终位置,它就不会更新它的状态,并且可拖动对象会在拖动之前快速返回"到它的初始位置.

the parent only needs to own the "non-moving position", and so the draggable would own it's "dragging position" but onmouseup it would call this.props.onChange(x, y) and defer the final decision to the parent. If the parent doesn't like where the draggable ended up, it would just not update it's state, and the draggable would "snap back" to it's initial position before dragging.

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

@ssorallen pointed out that, because "draggable" is more an attribute than a thing in itself, it might serve better as a mixin. My experience with mixins is limited, so I haven't seen how they might help or get in the way in complicated situations. This might well be the best option.

这篇关于使 React 组件/div 可拖动的推荐方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆