Go to comments

JavaScript 拖拽事件

一、拖拽

拖拽的要求是当鼠标在方块上面时,按下鼠标键挪动,方块跟着鼠标挪动,然后抬起鼠标键方块停止,再挪动鼠标这个方块不跟着鼠标挪动了,这是拖拽的一个过程,下面来写这个拖拽。

1、首先获取鼠标移动的位置

首先鼠标移动到每一位置的时候,记录一下鼠标移动位置的点,在document上绑定一个事件onmousemove,当鼠标移动的时候触发这个事件

document.onmousemove = function(e){

    var event = e || window.event; // "window.event"只有在全局的时候可以换省略"window"在局部不能省略"window.event"。

    console.log(event.clientY +" "+ event.clientX); // "e.clientY/e.clientX"记录当前鼠标点的位置

}

在页面移动鼠标,能把鼠标的坐标点记录下来

2、把鼠标移动的坐标,放到方块元素里面

有了鼠标坐标点位置,把这个坐标点的位置放到红色方块里面去,红色方块就跟着鼠标动了。

注意:div元素的left、top这两个属性必须设置为数字0,不然默认值是auto

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    var div = document.getElementsByTagName('div')[0]; // 选中div元素

    document.onmousemove = function(e){
        var e = e || window.event;
        console.log(e.clientY +" "+ e.clientX);

        div.style.top = e.clientY + 'px';
        div.style.left = e.clientX + 'px';
    }
    
</script>

鼠标可以拖动方块元素了,但动的不太好,移动时鼠标总是在方块元素的左上角

3、把事件顺序写好

1). 先不让div直接移动 div.onmousemove,

2). 先鼠标按下之后 div.onmousedown

3). 然后才绑定document,事件移动document.onmousemove

这样在红色方块上用鼠标按下,按完之后就拖拽着红色方块移动了

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    var div = document.getElementsByTagName('div')[0];

    div.onmousedown = function(e){ // 1. 先div.onmousedown按下去之后

        document.onmousemove = function(e){ // 2. 绑定一个事件"document.onmousemove
            var e = e || window.event; 
            div.style.top = e.clientY + 'px';
            div.style.left = e.clientX + 'px';
        }

    }
    
</script>

4). 然后鼠标按键抬起之后,取消移动onmousemove事件

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    var div = document.getElementsByTagName('div')[0];

    div.onmousedown = function() {

        div.onmousemove = function(e){ // 1. 这不设置document.onmousedown,设置div.onmousedown也行,设置div更精准
            var e = e || window.event; 
            div.style.top = e.clientY + 'px';
            div.style.left = e.clientX + 'px';
        }

        div.onmouseup = function(){ // 2. 鼠标抬起也设置在div上
            div.onmousemove = null; // 3. 然后鼠标抬起取消这个事件
        }
    }
    
</script>

点击拖走的过程完成了,但有个小问题鼠标在div的左上角,应该鼠标点击哪,哪就着跟拖走。

4、解决鼠标在div左上角的问题

我们设置鼠标当前的位置直接是方块的top和left,但是top和left是方块的左顶点,鼠标设置成左顶点肯定少了一个距离,把距离算上就行了。

鼠标当前的位置加上这个距离,再赋给方块左上角就行了,这个距离怎么求?

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    var div = document.getElementsByTagName('div')[0],
        disX,
        disY;

    div.onmousedown = function(e) {

        var e = e || window.event;
                
        // 求第一次鼠标点击的时候"点":  e.pageX
        // 方块左上角的距离:            div.style.left

        disX = e.pageX - parseInt(div.style.left); //  求鼠标当前点距方块left少的这个距离
        disY = e.pageY - parseInt(div.style.top);  //  求鼠标当前点距方块top少的这个距离

        div.onmousemove = function(e){
            var e = e || window.event; 
            div.style.top = e.clientY - disY + 'px';    // 减去这个距离
            div.style.left = e.clientX - disX + 'px';   // 减去这个距离
        }

        div.onmouseup = function(){
            div.onmousemove = null;
        }
    }
    
</script>

这样一个方块拖拽的基本功能就完成了,但是还是不好,比如飞快的往左上角一拖鼠标就出去了,但是鼠标还没抬起来,问题出那?

5、解决

我们把事件onmousemove绑定到div上了,只有在div上面挪动鼠标才能拖动,要知道鼠标的挪动是受系统监控的。

鼠标挪动是靠屏幕的帧频系统来监控的,每一秒鼠标可以够挪动多少下。比如每一秒鼠标可能挪动一百下,但是每一秒系统对事件的监听达不到一百次。

也就是说系统要监听什么时候发生事件,可能还没等系统反应过来鼠标已挪出去了,可能10毫秒监听一次什么时候挪,但你一毫秒就挪出了,系统都没监听到鼠标。

鼠标挪动的频次太快了,监听事件的频次没有那么快,所以鼠标都出了div的方块了,系统都没监听到鼠标在div上移动,还是div的面积太小了。

还想让鼠标随意的挪那么快的挪动,还想让div跟住鼠标怎么办?

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    var div = document.getElementsByTagName('div')[0],
        disX,
        disY;

    div.onmousedown = function(e) {

        disX = e.pageX - parseInt(div.style.left);
        disY = e.pageY - parseInt(div.style.top);

		// div.onmousemove = function(e){
		// 鼠标移动跟div没有关系
		// 把div改成doucment上触发解除事件,在document上怎么挪都不出去document是整个屏幕。
        document.onmousemove = function(e){
            var e = e || window.event; 
            div.style.top = e.clientY - disY + 'px';
            div.style.left = e.clientX - disX + 'px';
        }

		// 这也跟着改成在doucment上触发解除事件
        document.onmouseup = function(){
            document.onmousemove = null;
        }
    }

</script>

二、封装拖拽drap()方法

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    function dray(elem) {

        var disX, disY;

        elem.onmousedown = function(e) {

            disX = e.pageX - parseInt(elem.style.left);
            disY = e.pageY - parseInt(elem.style.top);

            document.onmousemove = function(e){
                var e = e || window.event; 
                elem.style.top = e.clientY - disY + 'px';
                elem.style.left = e.clientX - disX + 'px';
            }

            document.onmouseup = function(){ 
                document.onmousemove = null;
            }
        }

    }

    var div = document.getElementsByTagName('div')[0];

    dray(div);
    
</script>


作业:

用事件监听的方式绑定事件,然后封装一个函数drag

拖拽addEvent是绑定事件兼容性写法,stopBubble取消冒泡,canceHandler阻止默认事件。

上面的鼠标位置还有一个简单的方法,直接把鼠标设置定位在方块中间的位置。

<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div>

<script>

    var div = document.getElementsByTagName('div')[0];

    div.onmousedown = function() { 

        this.innerHTML = '别放开';

        div.onmousemove = function(e){
            var e = e || window.event; 
            div.style.top = e.clientY - 100/2 + 'px';
            div.style.left = e.clientX - 100/2 + 'px';
        }

        div.onmouseup = function(){
            div.onmousemove = null; 
            this.innerHTML = '休息一会吧';
        }
    }
    
</script>

三、setCapture()

拓展一下,这是一个过时的问题,但有些面试官会问一下符合他那个年代的问题,他会问什么是"事件获取"?

回答addEventListener第三个参数为true的时候,面试官还会问你还有没有其它形式的捕获,他说的什么意思呢?

我们说事件处理模型一个是冒泡一个是捕获这是毋庸置疑的,他说的第二种捕获不是事件处理模型,而是一种真实的事件获取的过程,用以解决这种拖拽鼠标容易出了div这样麻烦事。

用于解决鼠标帧频比事件监听帧频要快的问题,我们是用document绑定这种方式解决的。

他不是这样解决的,还有一种方法也叫事件捕获仅在IE里面好使叫"div.setCapture()"是个方法,执行完这个方法,这个div会获取捕获页面上发生的所有的事件,硬捕获到自己身上。

div.setCapture();

比如鼠标挪出div了,在其它地方发生的任何事情都算到div自己身上,这也叫事件获取依然能解决刚才的问题。

用完后用对应的方法"div.releaseCapture()"给释放了,这两个函数是对应的。

div.setCapture();

div.releaseCapture();

但这两个方法记住就行不用会操作,因为只有IE能用也不通用。

"Capture"获得、博得的意思。



Leave a comment 0 Comments.

Leave a Reply

换一张