質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

1回答

2551閲覧

Reactで要素をドラッグ&ドロップで移動させたい

serona

総合スコア25

ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

1グッド

2クリップ

投稿2018/02/22 02:42

編集2022/01/12 10:55

前提・実現したいこと

こちらのサイト様で説明していることを、
Reactで実現したいのですが、いまいち上手く行きません…。
(Material-UIを利用しています。)

該当のソースコード

これで一応動いたのですが、
マウスを素早く動かすと、要素がついていけてないような感じで、移動が止まってしまいます。
ゆっくりマウスを動かしているうちは、期待通り動きます。
素早く動かしてもついてくるようにしたいのですが、
どこを修正したらいいのでしょうか…
よろしくお願いします><

追記

~~恐らく、this.setState()で値を設定してから要素がレンダリングされるまでに、僅かな時間差があることが原因だと思われます。
上記のサイト様では、onMouseMoveイベントで直接要素の位置を変更しているのに対し、
Reactの場合はイベント発生時に値を変更(handleMove)し、変更があったことを確認してから新しい値でレンダリングする、という流れのため、
ゆっくりマウスを動かしているうちは問題ないものの、
激しくマウスを動かすと、「実際のマウスの位置」と、「変更前の値でレンダリングされている要素の位置」に差ができ
onMouseLeaveイベントが発生してしまう…ということなのだろうと思います。
これはもう、Reactのstateで要素の位置を管理すること自体諦めるしか無いのでしょうか…
回答お待ちしています><
~~

Javascript

1import React from 'react'; 2import PropTypes from 'prop-types'; 3import { withStyles } from 'material-ui/styles'; 4 5const styles = (theme) => ({ 6 box: { 7 padding: theme.spacing.unit * 2, 8 height: 100, 9 width: 100, 10 backgroundColor: 'red' 11 cursor: 'move', 12 position: 'absolute', 13 zIndex: 1000, 14 }, 15}); 16 17class TestComponent extends React.Component { 18 constructor(props) { 19 super(props); 20 this.state = { 21 isDrag: false, 22 x: 0, 23 y: 0, 24 top: 0, 25 left: 0, 26 }; 27 } 28 29 handleDown = (e) => { 30 const item = this.node; 31 const x = e.pageX - item.offsetLeft; 32 const y = e.pageY - item.offsetTop; 33 this.setState({ isDrag: true, x, y }); 34 } 35 36 handleMove = (e) => { 37 if (this.state.isDrag) { 38 e.preventDefault(); 39 40 this.setState({ 41 top: e.pageY - this.state.y, 42 left: e.pageX - this.state.x, 43 }); 44 } 45 } 46 47 handleUp = () => this.setState({ isDrag: false }); 48 49 render() { 50 const { top, left } = this.state; 51 const { classes } = this.props; 52 return ( 53 <div 54 role="presentation" 55 ref={(node) => { this.node = node; }} 56 onMouseDown={this.handleDown} 57 onMouseMove={this.handleMove} 58 onMouseUp={this.handleUp} 59 onMouseLeave={this.handleUp} 60 className={classes.box} 61 style={{ top, left }} 62 > 63 テスト 64 </div> 65 ); 66 } 67} 68 69TestComponent.propTypes = { classes: PropTypes.object.isRequired }; 70 71export default withStyles(styles)(TestComponent); 72

さらに追記

一度、サイト様に記載されているコードをそのまま記述してみましたところ、なんと同じ症状が発生しましたOTL
サイト様のページでは、Div要素はスムーズに動いているので、不可能ではないはずなのですが…。
こちらがCodePenで試したコードです。
CSSを少し編集したくらいで、JavaScriptのコードはコピペです。一切編集していません。

追記していた予想は外れていたようで…一向に原因がわかりません。助けてください(TmT)

og24715👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

よっ

試してみました

修正内容

  • handleDownのメソードの書き方
  • handleMoveのメソードの書き方
  • handleUpのメソードの書き方
  • constructorで(handleDown,handleMove,handleUp)にbindを追加 (そうしないと、setStateが使えないです。)

サンプルリンク :

http://study.jeromedupuis.net/teratail/react/#/114600

## コード 

サンプルでwithThemeを使ってないです。

import React, { Component } from 'react' const box = { padding:20, height: 100, width: 100, backgroundColor: 'red', cursor: 'move', position: 'absolute', zIndex: 1000, } class Teratail114600 extends Component { constructor(props) { super(props); this.state = { isDrag: false, x: 0, y: 0, top: 0, left: 0, }; this.handleDown = this.handleDown.bind(this) this.handleMove = this.handleMove.bind(this) this.handleUp = this.handleUp.bind(this) } handleDown(e) { const item = this.node; const x = e.pageX - item.offsetLeft; const y = e.pageY - item.offsetTop; this.setState({ isDrag: true, x, y }); } handleMove(e) { if (this.state.isDrag) { e.preventDefault(); this.setState({ top: e.pageY - this.state.y, left: e.pageX - this.state.x, }); } } handleUp() { this.setState({ isDrag: false }) } render() { const { top, left } = this.state; const { classes } = this.props; return ( <div role="presentation" ref={(node) => { this.node = node; }} onMouseDown={this.handleDown} onMouseMove={this.handleMove} onMouseUp={this.handleUp} onMouseLeave={this.handleUp} style={ { ...box, top, left } } > テスト </div> ); } } export default Teratail114600

加記 :

モバイル端末で使いたかったら、
onTouchStart
onTouchMove
onTouchEnd
を忘れないように

:)

投稿2018/02/22 03:55

編集2018/02/22 03:58
jerome.dupuis

総合スコア172

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

serona

2018/02/22 05:32

アロー関数式だと、constructorでbind書かなくてもsetState動作するようだったのでいつもこうしていました… 記載して頂いたサンプルリンクについては、私が試したコードと同じ動作になっていたので こちらは質問した問題についての回答ではなく、ソースコードの書き方に関する修正、という解釈でよかったでしょうか? あと、加記の件については了承しておりますので大丈夫です! 丁寧にありがとうございます(*^^*)
jerome.dupuis

2018/02/22 07:57

コーディングが日本語が分からなくても、色々伝えることができます。 日本語で説明するのは大変ですので、そのまま回答します :)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問