zoukankan      html  css  js  c++  java
  • 再谈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拖拽及思考》的续篇,看不懂的话可以先看一下。

    持续学习中。。。。

  • 相关阅读:
    动态存储区(堆)、动态存储区(栈)、静态存储区、程序代码区
    auto, extern, register, static
    #include <iomanip>
    use
    ZooKeeper某一QuorumPeerMain挂了
    python 中的 字符串 列表 元祖 字典
    JAVA的23种设计模式
    spark job分析
    Spark1
    SQL三大范式
  • 原文地址:https://www.cnblogs.com/LuckyWinty/p/5347559.html
Copyright © 2011-2022 走看看