JavaScript事件模拟元素拖动

一、前言:

最近要实现一个元素拖放效果,鼠标拖动元素并且定位元素,首先想到的是HTML5中的拖放,在HTML5中,有一个draggable属性,且有dragstart, dragover, drop等事件,主要是通过event.dataTransfer对象方法,在dragstart事件中设置数据event.dataTransfer.setData(); 在drop事件中获取数据event.dataTransfer.getData();但是它并不能实现元素的实时拖放效果,因此还是需要用鼠标事件来模拟元素的拖放。

 

二、实例示图 

 

JavaScript事件模拟元素拖动

 

三、实现原理:

1、思路:鼠标依次触发mousedown, mousemove, mouseup事件,在mousemove事件中实时计算元素新位置并且定位元素,

在mouseup事件中注销mousemove,mouseup事件。

 

2、重点:如果所有事件都绑定在拖动元素上,当鼠标移动速度很快,以至于离开了拖动的元素,那么就不会执行mousemove,

mouseup事件处理程序,因此要想让mousemove,mouseup事件处理实时执行,必须将它们绑定到document元素上;

 

四、插件源码:

$.fn.extend({

    /**

     * 

     * 扩展jQuery原型,实现鼠标事件模拟元素拖动

     * drag中的回调函数this指向被拖动元素

     * @ method: drag

     * @ use: $( selector ).drag( dragStart, dragMove, dragEnd )

     * @ param { function } 第一个参数,准备拖动处理函数

     * @ param { function } 第二个参数,拖动中处理函数

     * @ param { function } 第三个参数,拖动结束处理函数 

     * @ reutrn { jQuery( selector ) }

     *

     */

    drag: function( dragStart, dragMove, dragEnd ) {

        function drag( dragElem, event ) {

            var offsetX, offsetY, beforePageX, beforePageY;



            if ( $.isFunction(dragStart) ) {

                dragStart.apply(dragElem, arguments);

            }



            // 移动前或移动中的元素位置

            offsetX = parseInt( $(dragElem).css('left'), 10 );

            offsetY = parseInt( $(dragElem).css('top'), 10 );



            // 移动前或移动中的鼠标位置

            beforePageX = event.clientX;

            beforePageY = event.clientY;



            if ( document.addEventListener ) {

                document.addEventListener('mousemove', moveHandle, false);

                document.addEventListener('mouseup', upHandle, false);

            }

            else if ( document.attachEvent ) {

                dragElem.setCapture(); // 将dragElem鼠标事件继承到文档进行捕获

                dragElem.attachEvent('onmousemove', moveHandle);

                dragElem.attachEvent('onmouseup', upHandle);

                dragElem.attachEvent('onlosecapture', upHandle);

            }



            // 鼠标移动事件处理

            function moveHandle (event) {

                var event = event || window.event;



                // 更新移动中或移动终止后的元素位置

                var x = offsetX + event.clientX - beforePageX;

                var y = offsetY + event.clientY - beforePageY;



                $(dragElem).css({

                    left: x + 'px',

                    top: y + 'px'

                });



                // 阻止事件传播

                if ( event.stopPropagation ){

                    event.stopPropagation();

                }

                else if ( event.cancleBubble ) {

                    event.cancleBubble = true;

                }



                if ( $.isFunction(dragMove) ) {

                    dragMove.apply(dragElem, arguments);

                }

            }



            // 鼠标弹起事件处理

            function upHandle (event) {

                if ( document.addEventListener ) {

                    document.removeEventListener('mousemove', moveHandle, false);

                    document.removeEventListener('mouseup', upHandle, false);

                }

                else if ( document.detachEvent ) {

                    dragElem.detachEvent('onlosecapture', upHandle);                

                    dragElem.detachEvent('onmouseup', upHandle);

                    dragElem.detachEvent('onmousemove', moveHandle);

                    dragElem.releaseCapture();

                }

                if ( event.stopPropagation ){

                    event.stopPropagation();

                }

                else if ( event.cancleBubble ) {

                    event.cancleBubble = true;

                }



                if ( $.isFunction(dragEnd) ) {

                    dragEnd.apply(dragElem, arguments);

                }

            }

        }

        $(this).each(function(){

            $(this).bind('mousedown', function(e){

                var dragElem = this,

                    event = e;

                drag(dragElem, event);

            });

        });

        return this;

    }

});

 

五、调用实例:

(function(){

    var dragEnd = false;

    $('.drag-elem').drag(

        function(){

            $(this).text('准备拖动').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });

        },

        function(){

            var offset = $(this).offset();

            dragEnd = true;

            $(this).text('拖动中(' +  offset.left + ',' + offset.top + ')' );

        },

        function(){

            if (dragEnd) {

                $(this).text('拖动结束');

                dragEnd = false;

            }

        }

    );

}());

 

六、完整实例代码

<!doctype html>

<html>

<head>

<meta charset="utf-8">

<title>jQuery drag</title>

<script src="http://code.jquery.com/jquery-1.10.1.js"></script>

<style>

.drag-elem {

    position: absolute;

    left: 10px;

    top: 20px;

    z-index: 999;

    width: 200px;

    height: 50px;

    cursor: move;

    background-color: #ccc;

    border: 5px solid green;

    font-size: 24px;

    line-height: 50px;

    text-align: center;    

}

</style>

</head>



<body>



<div class="drag-elem"></div>



<script>

$.fn.extend({

    /**

     * 

     * 扩展jQuery原型,实现鼠标事件模拟元素拖动

     * drag中的回调函数this指向被拖动元素

     * @ method: drag

     * @ use: $( selector ).drag( dragStart, dragMove, dragEnd )

     * @ param { function } 第一个参数,准备拖动处理函数

     * @ param { function } 第二个参数,拖动中处理函数

     * @ param { function } 第三个参数,拖动结束处理函数 

     * @ reutrn { jQuery( selector ) }

     *

     */

    drag: function( dragStart, dragMove, dragEnd ) {

        function drag( dragElem, event ) {

            var offsetX, offsetY, beforePageX, beforePageY;



            if ( $.isFunction(dragStart) ) {

                dragStart.apply(dragElem, arguments);

            }



            // 移动前或移动中的元素位置

            offsetX = parseInt( $(dragElem).css('left'), 10 );

            offsetY = parseInt( $(dragElem).css('top'), 10 );



            // 移动前或移动中的鼠标位置

            beforePageX = event.clientX;

            beforePageY = event.clientY;



            if ( document.addEventListener ) {

                document.addEventListener('mousemove', moveHandle, false);

                document.addEventListener('mouseup', upHandle, false);

            }

            else if ( document.attachEvent ) {

                dragElem.setCapture(); // 将dragElem鼠标事件继承到文档进行捕获

                dragElem.attachEvent('onmousemove', moveHandle);

                dragElem.attachEvent('onmouseup', upHandle);

                dragElem.attachEvent('onlosecapture', upHandle);

            }



            // 鼠标移动事件处理

            function moveHandle (event) {

                var event = event || window.event;



                // 更新移动中或移动终止后的元素位置

                var x = offsetX + event.clientX - beforePageX;

                var y = offsetY + event.clientY - beforePageY;



                $(dragElem).css({

                    left: x + 'px',

                    top: y + 'px'

                });



                // 阻止事件传播

                if ( event.stopPropagation ){

                    event.stopPropagation();

                }

                else if ( event.cancleBubble ) {

                    event.cancleBubble = true;

                }



                if ( $.isFunction(dragMove) ) {

                    dragMove.apply(dragElem, arguments);

                }

            }



            // 鼠标弹起事件处理

            function upHandle (event) {

                if ( document.addEventListener ) {

                    document.removeEventListener('mousemove', moveHandle, false);

                    document.removeEventListener('mouseup', upHandle, false);

                }

                else if ( document.detachEvent ) {

                    dragElem.detachEvent('onlosecapture', upHandle);                

                    dragElem.detachEvent('onmouseup', upHandle);

                    dragElem.detachEvent('onmousemove', moveHandle);

                    dragElem.releaseCapture();

                }

                if ( event.stopPropagation ){

                    event.stopPropagation();

                }

                else if ( event.cancleBubble ) {

                    event.cancleBubble = true;

                }



                if ( $.isFunction(dragEnd) ) {

                    dragEnd.apply(dragElem, arguments);

                }

            }

        }

        $(this).each(function(){

            $(this).bind('mousedown', function(e){

                var dragElem = this,

                    event = e;

                drag(dragElem, event);

            });

        });

        return this;

    }

});

</script>





<script>

(function(){

    var dragEnd = false;

    $('.drag-elem').drag(

        function(){

            $(this).text('准备拖动').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });

        },

        function(){

            var offset = $(this).offset();

            dragEnd = true;

            $(this).text('拖动中(' +  offset.left + ',' + offset.top + ')' );

        },

        function(){

            if (dragEnd) {

                $(this).text('拖动结束');

                dragEnd = false;

            }

        }

    );

}());

</script>

</body>

</html>
View Code

 

源码更新 2014/02/19

$.fn.extend({

    /**

     * 

     * 扩展jQuery原型,实现鼠标事件模拟元素拖动

     * drag中的回调函数this指向被拖动元素

     * @ method: drag

     * @ use: $( selector ).drag( dragStartFn, dragMoveFn, dragEndFn )

     * @ param { function } 第一个参数,准备拖动处理函数

     * @ param { function } 第二个参数,拖动中处理函数

     * @ param { function } 第三个参数,拖动结束处理函数 

     * @ reutrn { jQuery( selector ) }

     *

     */

    drag: function( dragStartFn, dragMoveFn, dragEndFn ) {

        function drag( target, e ) {

            var offsetX, offsetY, beforePageX, beforePageY;



            if ( $.isFunction(dragStartFn) ) {

                dragStartFn.apply(target, arguments);

            }



            // 移动前或移动中的元素位置

            offsetX = parseInt( $(target).css('left'), 10 ) || 0;

            offsetY = parseInt( $(target).css('top'), 10 ) || 0;



            // 移动前或移动中的鼠标位置

            beforePageX = e.clientX;

            beforePageY = e.clientY;



            $(document).bind('mousemove', moveHandle)

                        .bind('mouseup', upHandle);



            // 鼠标移动事件处理

            function moveHandle (e) {

                // 更新移动中或移动终止后的元素位置

                var x = offsetX + e.clientX - beforePageX;

                var y = offsetY + e.clientY - beforePageY;



                $(target).css({

                    left: x + 'px',

                    top: y + 'px'

                });

                if ( $.isFunction(dragMoveFn) ) {

                    dragMoveFn.apply(target, arguments);

                }

                // 阻止浏览器默认行为(鼠标在拖动图片一小段距离,会出现一个禁止的小提示,即:图片不能再拖动)

                e.preventDefault();

            }



            // 鼠标弹起事件处理

            function upHandle (e) {

                $(document).unbind('mousemove', moveHandle)

                        .unbind('mouseup', upHandle);

                if ( $.isFunction(dragEndFn) ) {

                    dragEndFn.apply(target, arguments);

                }

            }

        }

        $(this).each(function(){

            $(this).bind('mousedown', function(e){

                drag(this, e);

            });

        });

        return this;

    }

});



// 调用实例

(function(){

    var dragEnd = false;

    $('div').drag(

        function(){

            $(this).html('<span>准备拖动</span>').css({ zIndex: 2 }).siblings().css({ zIndex: 1 });

        },

        function(){

            var offset = $(this).offset();

            $(this).html('<span>拖动中(' +  offset.left + ',' + offset.top + ')</span>' );

        },

        function(){

            $(this).html('<span>拖动结束</span>')

        }

    );

    $('img').drag();

}());
View Code

 

 

你可能感兴趣的:(JavaScript)