前幾天寫的那個拖拽,自己留下的疑問。。。這次在熱心博友的提示下又修正了一些小小的bug,也加了拖拽的邊緣檢測部分。。。就再聊聊拖拽吧
一、不要直接操作dom元素
react中使用了虛擬dom的概念,目地就是要盡量避免直接操作dom元素,所以我們在對dom元素進行操作的時候需要注意,我之前為了獲取form的參數就直接用了var dragBox=document.getElementById('form')去找dom,但是其實記錄from的初始位置,可以在其子組件更新父組件參數的時候調用。即在MyFrom組件中獲取,如下代碼:
onChildChanged:function(newState){ /*以下為修改處*/ var computedStyle=document.defaultView.getComputedStyle(ReactDOM.findDOMNode(this.refs.dragBox),null); newState.left=computedStyle.left; newState.top=computedStyle.top; /*以上為修改處*/ this.setState(newState); },
這樣就可以直接在父組件中操作自己,而不是在子組件中調用。
二、onmousemove和onmouseup事件應該綁定到document上
拖拽事件中,當鼠標在DragArea中按下後,就應該檢測鼠標在document中移動的距離及何時彈起。否則直接綁定在form的話會有一個不雅的地方,就是拖動條拖動邊緣附近的時候,如果鼠標速度快一點會失效,鼠標再回來拖動條會自動吸上鼠標。因此利用react初始化階段的componentDidMount函數,這個函數是組件被裝載後才會被調用,也就是說調用這個方法的時候,組件已經被渲染到了頁面上,這個時候可以修改DOM。也就是說此時把相應事件再綁定到document上面,如下代碼:
componentDidMount:function(){ document.addEventListener('mousemove',(e)=>{this.move(e);},false);/*ES6新特性,箭頭函數,需要依賴jsx編譯工具才能正確運行*/ document.addEventListener('mouseup',(e)=>{this.endDrag(e);},false); },
這樣就可以消除那個小小的bug啦!
三、增加邊緣檢測
一般情況下的拖拽,我們都是不希望能夠拖出可視窗口之外的,因此這就需要檢測。檢測四個方向上的位置,即上、下、左、右。顯然,上的距離top和左邊left的距離必須要大於等於0,下邊和右的距離必須要小於視口大小減去from本身的元素寬高。
具體代碼:
move:function(event){ var e = event ? event : window.event; var dBox=ReactDOM.findDOMNode(this.refs.dragBox); if (this.state.flag) { var nowX = e.clientX, nowY = e.clientY; var disX = nowX - this.state.currentX, disY = nowY - this.state.currentY; /*增加拖拽范圍檢測*/ var currentLeft=parseInt(this.state.left) + disX; var currentTop=parseInt(this.state.top) + disY; var docX=document.documentElement.clientWidth||document.body.clientWidth; var docY=document.documentElement.clientHeight||document.body.clientHeight; if(currentLeft<=250){//檢測屏幕左邊,因為我這裡的初始居中是利用了負1/2的盒子寬度的margin,所以用250px判斷邊界 dBox.style.left=250+"px"; }else if(currentLeft>=(docX-dBox.offsetWidth+250)){ //檢測右邊 dBox.style.left=(docX-this.state.offsetX)+"px"; }else{ dBox.style.left =currentLeft+ "px"; } if(currentTop<=200){ //檢測屏幕上邊,因為我這裡的初始居中是利用了負1/2的盒子高度的margin,所以用200px判斷邊界
dBox.style.top=200+"px";
}else if(currentTop>=(docY-dBox.offsetHeight+200)){ //檢測下邊
dBox.style.top=(docY-this.state.offsetY)+"px";
}else{
dBox.style.top = currentTop + "px";
}
}
PS:新的代碼已經更新在我的github上面,大家可以研究一下。
本文實質上為《React.js實現原生js拖拽及思考》的續篇,看不懂的話可以先看一下。
持續學習中。。。。