再谈React.js实现原生js拖拽效果
前几天写的那个拖拽,自己留下的疑问。。。这次在热心博友的提示下又修正了一些小小的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拖拽及思考》的续篇,看不懂的话可以先看一下。
持续学习中。。。。