Javascript学习笔记18 高级技巧(自定义事件 拖放)

自定义事件

事件是一种叫做观察者的设计模式,观察者模式由两类对象组成:主体和观察者。主体负责发布事件,同时观察者知道通过订阅这些事件来观察主体。主体可以独自存在并正常运作即使观察者不存在。在DOM结构中,DOM元素便是主体,事件处理代码便是观察者
自定义事件背后的概念是创建一个管理事件的对象,让其他对象监听那些事件。

function EventTarget(){     //用于管理事件的对象
    this.handlers = {};    //handler属性用于存储各种事件类型的处理函数
} 
EventTarget.prototype = {     
    constructor: EventTarget,

    addHandler: function(type, handler){   //添加事件处理程序,接受两个参数,事件类型和处理函数
         if (typeof this.handlers[type] == "undefined"){  //如果是新的事件类型
              this.handlers[type] = [];   //新建一个数组,用于存储新事件类型的一系列处理函数
         }
         this.handlers[type].push(handler);  //将处理函数推入对应事件类型的数组中
     }, 

    fire: function(event){   //触发事件,接受一个对象,包含事件类型和处理函数的输入参数
         if (!event.target){  //设置event对象的target属性
             event.target = this;
         }
         if (this.handlers[event.type] instanceof Array){
             var handlers = this.handlers[event.type];   //取出指定事件类型的处理函数数组
             for (var i=0, len=handlers.length; i < len; i++){  //依次调用数组中的每一个处理函数
                 handlers[i](event); 
            }
         }
     },

     removeHandler: function(type, handler){   //移除事件
        if (this.handlers[type] instanceof Array){ 
            var handlers = this.handlers[type]; 
            for (var i=0, len=handlers.length; i < len; i++){  //寻找对应事件函数在数组中的下标 
                if (handlers[i] === handler){ 
                    break;
                 }
             }
             handlers.splice(i, 1);   //删除对应下标的处理函数
          }
      }
};

使用例子

function handleMessage(event){
    alert("Message received:" + event.message);
}

var target = new EventTarget();

target.addHandler("message",handleMessage);   //添加一个事件处理程序

target.addHandler({type:"message", message:"Hello world"});   //触发事件处理程序

target.removeHandler("message",handleMessage);   //删除事件处理程序

拖放

实现拖放的基本思想是利用mousemove事件,使绝对定位元素的坐标跟随鼠标指针的位置,在鼠标按下的时候(mousedown事件)启用拖放,在鼠标释放的时候(mouseup事件)关闭拖放,就可以实现。

var DragDrop = function(){
    var dragging = null;     //用于保存拖放的对象
    function handleEvent(event){   //事件处理程序
        switch(event.type){
            case "mousedown":   //鼠标按下,若元素可拖放,则启动拖放
                if (event.target.className.indexOf("draggable") > -1){
                    dragging = event.target;
                }
                break;
            case "mousemove":  //拖放过程中使对象跟随鼠标移动
                if (dragging !== null){
                    dragging.style.left = event.clientX + "px";
                    dragging.style.top = event.clientY + "px";
                }
                break;
            case "mouseup":   //关闭拖放
                dragging = null;
                break;
        }
    }

    return {
        enable:function(){    //启用拖放功能
            document.addEventListener("mousedown",handleEvent,false);
            document.addEventListener("mousemove",handleEvent,false);
            document.addEventListener("mouseup",handleEvent,false);
        },
        disable:function(){  //启用拖放功能
            document.removeEventListener("mousedown",handleEvent,false);
            document.removeEventListener("mousemove",handleEvent,false);
            document.removeEventListener("mouseup",handleEvent,false);
        }
    } 
}();

上述例子,当鼠标开始移动时,元素好像是跳了一下,显得很不自然。原因在于,元素的left和top坐标默认为元素的左上角那一点。要想保持用户点击时那一点的坐标与鼠标坐标保持一致,需要计算鼠标与元素左上角的坐标差值

    var dragging = null;     //用于保存拖放的对象

    var diffX = 0,   //鼠标和元素左上角X方向上的差值
        diffY = 0;  //鼠标和元素左上角Y方向上的差值
    function handleEvent(event){   //事件处理程序
        switch(event.type){
            case "mousedown":   //鼠标按下,若元素可拖放,则启动拖放
                if (event.target.className.indexOf("draggable") > -1){
                    dragging = event.target;
                    diffX = event.clientX - event.target.offsetLeft;
                    diffX = event.clientY - event.target.offsetTop;
                }
                break;
            case "mousemove":  //拖放过程中使对象跟随鼠标移动
                if (dragging !== null){
                    dragging.style.left = (event.clientX - diffX) + "px";
                    dragging.style.top = (event.clientY - diffY) + "px";
                }
                break;
            case "mouseup":   //关闭拖放
                dragging = null;
                break;
        }
    }

以上只是实现了拖放功能,但是缺少事件,不知道什么时候拖放开始和结束,因此可以结合之前的自定义事件,为拖放添加dragstart,drag,dragend三个自定义事件

var DragDrop = function(){
    var dragging = null;     

    var diffX = 0,   
        diffY = 0;

    var dragdrop = new EventTarget();  //创建一个管理自定义事件的对象
    function handleEvent(event){   
        switch(event.type){
            case "mousedown":   
                if (event.target.className.indexOf("draggable") > -1){
                    dragging = event.target;
                    diffX = event.clientX - event.target.offsetLeft;
                    diffX = event.clientY - event.target.offsetTop;
                    dragdrop.fire({type:"dragstart",target:dragging,
                                    x:event.clientX,y:event.clientY});  //触发dragstart事件
                }
                break;
            case "mousemove":  
                if (dragging !== null){
                    dragging.style.left = (event.clientX - diffX) + "px";
                    dragging.style.top = (event.clientY - diffY) + "px";
                    dragdrop.fire({type:"drag",target:dragging,
                                    x:event.clientX,y:event.clientY});  //触发drag事件
                }
                break;
            case "mouseup":
                dragdrop.fire({type:"dragend",target:dragging,
                                    x:event.clientX,y:event.clientY});  //触发dragend事件   
                dragging = null;
                break;
        }
    }

    dragdrop.enable = function(){    
            document.addEventListener("mousedown",handleEvent,false);
            document.addEventListener("mousemove",handleEvent,false);
            document.addEventListener("mouseup",handleEvent,false);
    };
    dragdrop.disable = function(){  
            document.removeEventListener("mousedown",handleEvent,false);
            document.removeEventListener("mousemove",handleEvent,false);
            document.removeEventListener("mouseup",handleEvent,false);
    };

    return dragdrop;  //返回事件对象

}();

添加事件处理程序

DragDrop.addHandler("dragstart",function(event){
    var status = document.getElementById("status");
    status.innerHTML = "start dragging" + event.target.id;  
}); 

DragDrop.addHandler("drag",function(event){
    var status = document.getElementById("status");
    status.innerHTML = "dragged" + event.target.id + "to" + event.x + "," + event.y;
}); 

DragDrop.addHandler("dragend",function(event){
    var status = document.getElementById("status");
    status.innerHTML = "droped" + event.target.id + "at" + event.x + "," + event.y;
}); 

猜你喜欢

转载自blog.csdn.net/zjw_python/article/details/80154398
今日推荐