JavaScript事件模擬元素拖動


一、前言:

最近要實現一個元素拖放效果,鼠標拖動元素並且定位元素,首先想到的是HTML5中的拖放,在HTML5中,有一個draggable屬性,且有dragstart, dragover, drop等事件,主要是通過event.dataTransfer對象方法,在dragstart事件中設置數據event.dataTransfer.setData(); 在drop事件中獲取數據event.dataTransfer.getData();但是它並不能實現元素的實時拖放效果,因此還是需要用鼠標事件來模擬元素的拖放。

 

二、實例示圖 

 

 

三、實現原理:

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM