1. 原因と考え方
私はネイティブの JS ドラッグ アンド ドロップ エフェクトを書きたいとずっと思っていて、最近は楽しく React を学習しています。そこで、このドラッグ アンド ドロップ効果を実現するために React を使用しました。
まず第一に、ドラッグ効果のアイデアは実際には非常に単純です。主に次の 3 つのステップがあります:
1. マウスダウン時に、ドラッグ可能なイベントを開始し、ドラッグされた要素の元の座標パラメータを記録します。
2. onmousemove の場合、マウスの移動距離をリアルタイムで記録し、ドラッグされた要素の最初のステージの座標パラメーターに基づいて新しい座標値を計算して設定します。
3. onmouseup 中に、ドラッグ可能なイベントを閉じて、新しい座標値を記録します。
注: 要素の位置は主に上と左の絶対位置によって決定されるため、ドラッグされた要素の CSS は絶対位置に設定する必要があります。
2. 補助ツール
補助ツールは主に、開発プロセスを効率的かつクールなものにします。このデモでは、gulp+browser-sync 開発ツールを皆さんにお勧めします。このデモでは、gulp の主な機能は、もちろん、react での jsx ファイルのリアルタイム コンパイルを設定することです。 , cssを書くとsassですが、sassのリアルタイムコンパイルの設定もできます。ブラウザ同期を使用する主な目的は、ページをリアルタイムで自動的に更新することです。通常、ページを作成して効果を確認するときは、F5 キーを押してブラウザを更新してからページを表示します。しかし、このプラグインを使用すると、コードの記述が完了したら、Ctrl+S を押して保存するだけで、新しいエフェクトがブラウザで自動的に更新され、表示できるようになります。
使用方法の詳細な説明:
インストール:
1. gulp をノード環境にインストールします。具体的なプロセスについては、私のブログ投稿「React.js を始めるために知っておくべきこと」を参照してください。
2. gulp-livereload をインストールするには、コマンドラインまたは git bash で「npm install --save-dev gulp-livereload」と入力します。
3. コマンドラインまたは git bash で「npm install --save-dev gulp-watch」と入力して gulp-watch をインストールします4. browser-sync をインストールするには、コマンドラインまたは git bash で「npm install --save-dev browser-sync」と入力します
構成と説明は図のとおりです。
3. コンポーネント構築ページの定義
注: ここでのコードの説明はすべて、react 関連モジュールがインストールされた後のものです。インストール プロセスについては、私のブログ投稿「react.js を始めるために知っておくべきこと」を参照してください。レンダリング:
コンポーネント分割のアイデア:
コンポーネントをより小さな部分に分割した方が良いと考えたので、入力とボタンをそれぞれ 1 つのコンポーネントにしました。
var React=require('react'); var MyInput=React.createClass({ render:function(){ return ( <div className="form-group"> <label htmlFor={this.props.labelId} className="col-sm-2 control-label{this.props.labelTip</label> <div className="col-sm-10"> <input name={this.props.name} type={this.props.type} onChange={this.props.onChange} className="form-control" id={this.props.labelId} placeholder={this.props.placeholder}/> </div> </div> ); } }); module.exports=MyInput;
var React=require('react'); var Button=React.createClass({ render:function(){ return ( <button type={this.props.type} className="loginButton">{this.props.ButtonTip}</button> ); } }) module.exports=Button;
記述後の親コンポーネント:
render:function(){ return ( <form className="form-horizontal" id="form" ref="dragBox" onSubmit={this.submitHandler} onMouseMove={this.move} onMouseUp={this.endDrag}> <DragArea callbackParent={this.onChildChanged} /> <div id="form-wrap"> <MyInput name="username" labelId={"userId"} labelTip={"用户名"} type={"text"} placeholder={"请输入用户名"} value={this.state.username} onChange={this.handleChange}/> <MyInput name="password" labelId={"pw"} labelTip={"密码"} type={"password"} placeholder={"请输入密码"} value={this.state.password} onChange={this.handleChange}/> <div className="form-group"> <div className="col-sm-offset-2 col-sm-10"> <div className="checkbox"> <label> <input name="checked" type="checkbox" checked={this.state.checked} onChange={this.handleChange} /> 记住我 </label> </div> </div> </div> <MyButton type={"submit"} ButtonTip={"登陆"}/> </div> </form> );
CSS スタイルを追加するとページが完成します。いよいよ、ここからが本題です! ! !
4. ドラッグ アンド ドロップを実装するための親コンポーネントと子コンポーネント間の通信
注: 達成したい効果は、サブコンポーネント DragArea でマウスを押すとフォーム全体がドラッグされることなので、DragArea がドラッグを開始し、フォームが応答します。したがって、親コンポーネントの一部の状態プロパティを最初に子コンポーネントに渡す必要があります。その後、DragArea 上でマウスが押されたときに、親コンポーネントの元の座標パラメータが子コンポーネント DragArea を介して検出される必要があります。親コンポーネントの状態プロパティを更新する必要があり、ドラッグが利用可能であることを親コンポーネントに伝えます。親コンポーネントから子コンポーネントに渡されるパラメータは直接渡されます。子コンポーネントは、親コンポーネントにパラメータを渡すためにイベントを渡す必要があります。したがって、親コンポーネントでそのような関数を定義します。
onChildChanged:function(newState){ //因为参数过多,所以把参数放到对象里面,通过对象来传 this.setState(newState); },
子コンポーネントの応答関数は次のとおりです:
startDrag:function(e){ var dragBox=document.getElementById('form'); var newState={}; var event=e||window.event; event.preventDefault(); var computedStyle=document.defaultView.getComputedStyle(dragBox,null); newState.left=computedStyle.left; newState.top=computedStyle.top; newState.currentX=event.clientX; newState.currentY=event.clientY; newState.flag=true; <span style="color: #0000ff;"> this.props.callbackParent(newState);</span> }
move:function(event){ var e = event ? event : window.event; //兼容IE的写法 if (this.state.flag) { var nowX = e.clientX, nowY = e.clientY; var disX = nowX - this.state.currentX, disY = nowY - this.state.currentY; ReactDOM.findDOMNode(this.refs.dragBox).style.left = parseInt(this.state.left) + disX + "px"; ReactDOM.findDOMNode(this.refs.dragBox).style.top = parseInt(this.state.top) + disY + "px"; } }, endDrag:function(){ var computedStyle=document.defaultView.getComputedStyle(ReactDOM.findDOMNode(this.refs.dragBox),null); this.setState({ left:computedStyle.left, top:computedStyle.top, flag:false }); }
この時点で、ドラッグ アンド ドロップが実装されました。
5. 振り返りとレビュー
1. 理論的には、ドラッグ効果はどの要素でも実現でき、ドラッグの考え方は同じなので、理論的には、各ドラッグプロセスの機能を抽出して Mixin にすることができます。繰り返し呼び出すことができます。これが私の最初のアイデアでしたが、パラメーターを渡したり、応答したり、要素をバインドしたりするときにいつも間違いを犯していました。調べてみてもreactやドラッグアンドドロップなどの簡単な記述方法はReact用の特殊なプラグインがいくつかあるだけで、私の現状では理解できませんでした。レベル。ということで、この書き方は一旦やめました。関連するアイデアをお持ちの専門家が私と共有できることを願っています。
2. 記事内のサブコンポーネントは、パラメータを取得するときに varragBox=document.getElementById('form'); を使用して dom を見つけます。これは、react のいくつかの概念に違反しているようです。しかし、子コンポーネントから親コンポーネントのdomを取得する方法がよくわかりません。親コンポーネントで refs=this.refs.dragBox を定義してみました。次に、それがサブコンポーネントに渡されますが、なぜブラウザがこれが dom ノードではないというエラーを報告し続けるのかわかりません。神に導きを求めてください。
3. ドラッグイベントを記述する一般的な方法は、ドキュメント上でmousemoveイベントとmouseupイベントを定義することですが、この場合、これら2つのイベントをreact内のドキュメント内で定義すると、関連するイベントのパラメータを追跡できません。そこで、から定義しました。もっと良い方法はありますか?シェアしてください!
4. 革命はまだ成功していません、同志たちはまだ努力する必要があります!
このデモは次の場所にアップロードされました: https://github.com/LuckyWinty/dragDemo
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。