1. ホーム
  2. javascript

[解決済み] Reactのコンポーネント/divをドラッグ可能にするおすすめの方法

2022-06-18 15:37:40

質問

私はドラッグ可能な(つまり、マウスで再配置可能な)Reactコンポーネントを作りたいと思っていますが、それは必然的にグローバルな状態と散在するイベントハンドラを含むように思われます。私は、私のJSファイルのグローバル変数で、汚い方法でそれを行うことができ、おそらく素敵なクロージャーインターフェイスでそれを包むことさえできましたが、私はReactとよりよくかみ合う方法があるかどうかを知りたいのです。

また、私は生のJavaScriptでこれをやったことがないので、特にReactに関連して、私がすべてのコーナーケースを処理したことを確認するために、専門家がそれをどのように行うかを見たいと思います。

ありがとうございます。

どのように解決するのですか?

これはブログの記事にすべきかもしれませんが、かなりしっかりした例があります。

コメントでうまく説明できるはずですが、質問があれば教えてください。

そして、これが遊ぶためのバイオリンです。 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) を呼び出します。

シナリオ2

親は移動しない位置だけを所有すればよいので、ドラッガブルはドラッグする位置だけを所有しますが、マウスアップ時に this.props.onChange(x, y) を呼び出し、最終的な決定を親に委ねます。親がドラッガブルの最終位置を気に入らない場合、状態を更新せず、ドラッガブルはドラッグする前の初期位置に戻るようになります。

ミキシンまたはコンポーネント?

ssorallen 氏は、"dragable" はそれ自体よりも属性であるため、mixin としてよりよく機能するかもしれないと指摘しました。私のミキシンの経験は限られているので、ミキシンがどのように役立つのか、あるいは複雑な状況で邪魔になるのかを見たことがありません。これは最良の選択かもしれません。