• 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
  • 相关阅读:
    Placing Rooks-CF 1342E
    Yet Another Counting Problem-CF 1342C
    [SDOI2016]齿轮
    Rinne Loves Xor
    Labyrinth CodeForces
    Nastya and Scoreboard
    Teacher Bo HDU
    Blood Cousins Return
    D Tree HDU
    设计模式学习笔记(八、行为型-策略模式)
  • 原文地址:https://www.cnblogs.com/yangjunhua/p/3319895.html
Copyright © 2020-2023  润新知