Javascript處理DOM元素事件

  DOM元素都有一些標準事件,一般使用時只要使用οnclick=function的方式就可以了,但是當需要爲DOM元素添加多個事件,刪除事件,或在用Javascript封裝控件的時候,爲封裝的控件添加自定義事件的時候,οnclick=function的方式就不夠用了,但是瀏覽器有addEventListener和attachEvent方法可供調用,從而模擬出類似於C#中的事件委託的事件觸發機制!

/*
* 功能:事件處理
* Author:LQB
* 時間:2009-1-4
* #include JCore.js
*/
var JEvents = function(){
    this.events={};
    
    this.addEvent = function(o){//添加事件
            if(typeof o == 'string'){/*strArg1,strArg2……的方式傳遞參數*/
                for(var i = 0, a = arguments, v; v = a[i]; i++){
                    v = v.toString().toLowerCase();
                    var enFX = v.indexOf("on")==0 ? v.substr(2) : v;
                    if(!this.events[enFX]){
                        this.events[enFX] = true;
                    }
                }
            }else{
                JCore.apply(this.events, o,false);
            }
    };
    this.addListener = function(eventName,fn,scope/*,Args……*/){//爲事件添加處理方法
            if(typeof(eventName)!="string"|| eventName.lenght==0)return;
            if(typeof(fn)!="function")return;
            eventName = eventName.toString().toLowerCase();
            var enFX = eventName.indexOf("on")==0 ? eventName.substr(2) : eventName;
            if(!this.events[enFX]){
                throw "Error! Event /"" + eName + "/" doesnt exist."
            }
            var sp = scope||window;
            var callArgs = Array.prototype.slice.call(arguments, 3);//從第4個參數開始
            callArgs = typeof(callArgs)!="undefined"?callArgs:[];
            var delegate = fn.createDelegate(callArgs,sp);//JCore支持
            
            //爲fn方法創建標記,在刪除事件時使用
            if(!fn.uid) {
                var time = new Date();
                fn.uid= ""+time.getMinutes()+time.getSeconds()+time.getMilliseconds();
            }
            //標記委託,在刪除事件綁定時使用
            delegate.uid = getCacheAttName(enFX,fn.uid);
            
            if(typeof(this.events[enFX])!="object")
                this.events[enFX]=[];
            this.events[enFX].push(delegate);//把方法添加到事件列表中
    };
    this.removeListener = function(eventName,fn){//移除事件綁定
            if(eventName && fn){
                eventName = eventName.toString().toLowerCase();
                var enFX = eventName.indexOf("on")==0?eventName.substr(2):eventName;
                var AttName = getCacheAttName(enFX,fn.uid);
                if(typeof(this.events[enFX])=="object"){//存在這個事件
                    var functions = this.events[enFX];
                    for(i=0;i<functions.length;i++){//依次查找每個方法
                        if(functions[i].uid===AttName){//找到,刪除
                            this.events[enFX].remove(functions[i]);
                            break;
                        }
                    }
                }
            }
    }
    this.fireEvent = function(eName,eventArg){//觸發事件
            eName = eName.toString().toLowerCase();
            var enFX = eName.indexOf("on")==0 ? eName.substr(2) : eName;
            var Arg = new Array();
            if(typeof(eventArg)!="undefined"){
                if(typeof(eventArg)=="array") Arg=eventArg;
                else Arg.push(eventArg);
            }
            if(typeof(this.events[enFX])=="object"){//存在此事件,同時添加了事件處理方法
                var functions = this.events[enFX];
                for(i=0;i<functions.length;i++){//依次觸發所有方法
                    functions[i].apply(window,Arg);
                }
            }
    }
    /*---------------------------------------私有方法--------------------------------------*/
    var getCacheAttName = function(eventName,fnuid){
            return "handle-"+eventName+"-"+fnuid;
    }
}

/*------------------------------------------------------以下是靜態方法,用於處理DOM element的事件-----------------------------------------*/
var JEventsExtendMethod = {
    cache : {//時間處理緩存,用於標記各個事件處理方法,在刪除事件時使用
            eventCache : {},
            setCache : function(el,Name,value){
                if(typeof(this.eventCache[el])!="object"){
                    this.eventCache[el]={length :1};
                }
                this.eventCache[el][Name]=value;
                this.eventCache[el].length++;
            },
            getCache : function(el,Name){
                if(typeof(this.eventCache[el]) =="object")
                    return this.eventCache[el][Name];
                else
                    return null;
            },
            removeCache : function(el,Name){
                if(typeof(this.eventCache[el]) =="object"){
                    delete this.eventCache[el][Name];//刪除屬性
                    this.eventCache[el].length--;
                }
                if(this.eventCache[el] && this.eventCache[el].length ==1)//清除
                    delete this.eventCache[el];
            }
    },
    getCacheAttName : function(eventName,fnuid){
        return "handle-"+eventName+"-"+fnuid;
    },
    bind : function(el,eventName,fn,scope/*,Args……*/){//爲elment添加事件處理方法
            if(typeof(el)=="undefined"||el==null)return;
            if(typeof(eventName)!="string"|| eventName.lenght==0)return;
            if(typeof(fn)!="function")return;
            var indexOfon = eventName.toString().toLowerCase().indexOf("on");
            var enIE = indexOfon==0?eventName:"on"+eventName;
            var enFX = indexOfon==0?eventName.substr(2):eventName;
            var sp = scope||window;
            var callArgs = Array.prototype.slice.call(arguments, 4);//從第5個參數開始
            callArgs = typeof(callArgs)!="undefined"?callArgs:[];
            var delegate = fn.createDelegate(callArgs,sp);//JCore支持
            if (el.addEventListener){//Mozilla系列,按隊列順序執行
                el.addEventListener(enFX, delegate, false);//第三個參數與觸發方式相關
            } else if (el.attachEvent){//非Mozilla系列,按堆棧順序執行(後加的事件先執行)
                el.attachEvent(enIE, delegate);
            } 
            //爲fn方法創建標記,在刪除事件時使用
            if(!fn.uid) {
                var time = new Date();
                fn.uid= ""+time.getMinutes()+time.getSeconds()+time.getMilliseconds();
            }
            if(!el.id){
                el.id = JCore.id(el,null);
            }
            //標記委託,在刪除事件綁定時使用
            var AttName = this.getCacheAttName(enFX,fn.uid);
            this.cache.setCache(el.id,AttName,delegate);
        },
    unbind : function(el,eventName,fn){//爲elment解除事件綁定
            if(typeof(el)=="undefined"||el==null)return;
            var indexOfon = eventName.toString().toLowerCase().indexOf("on");
            var enIE = indexOfon==0?eventName:"on"+eventName;
            var enFX = indexOfon==0?eventName.substr(2):eventName;
            var AttName = this.getCacheAttName(enFX,fn.uid);
            var delegate = this.cache.getCache(el.id,AttName);
            if(delegate){
                if (el.removeEventListener){//Mozilla系列
                    el.removeEventListener(enFX, delegate, false);
                } else if (el.detachEvent){//非Mozilla系列
                    el.detachEvent(enIE, delegate);
                }
            }
            //刪除事件緩存
            this.cache.removeCache(el.id,AttName);
        }
}
JCore.apply(JEvents,JEventsExtendMethod);

/*--------------------------------對event的參數包裝---------------------------------*/
var JEventWrap = function(event){
    this.xtype="EventWrap";
    this.data=null;
    
    this.srcElement = null; //發生事件的文檔元素
    this.button = null;     //[FX:0-左鍵,1-中間鍵,2-右鍵][IE:1-左鍵,2-右鍵,4-中鍵](僅對onmousedown, onmouseup,onmousemove有效)
    this.type = null;
    this.clientX = 0;       //鼠標指針相對客戶區或瀏覽器窗口的X座標(標準屬性)
    this.clientY = 0;       //鼠標指針相對客戶區或瀏覽器窗口的Y座標(標準屬性)
    this.offsetX = 0;       //鼠標指針相對於源元素的X座標(兼容屬性)(IE)
    this.offsetY = 0;       //鼠標指針相對於源元素的Y座標(兼容屬性)(IE)
    this.screenX = 0;       //鼠標指針相對於用戶顯示器的左上角X座標(兼容屬性)(FX)
    this.screenY = 0;       //鼠標指針相對於用戶顯示器的左上角Y座標(兼容屬性)(FX)
    this.altKey = false;    //是否Alt鍵
    this.ctrlKey = false;   //是否Ctrl鍵,
    this.shitfKey = false;  //是否Shift鍵
    this.keyCode = 0;
    
    
    this.originaEvent = null;   //未包裝的原始事件對象
    /*----構造-----*/
    if(event){
        if(event.srcElement){//IE
           this.srcElement = event.srcElement;
           this.offsetX = event.offsetX;
           this.offsetY = event.offsetY;
           this.button = event.button;
        }
        else{
           this.srcElement = event.target;
           this.offsetX = event.clientX - event.target.offsetLeft;
           this.offsetY = event.clientY - event.target.offsetTop;
        }
       
        this.type = event.type;
        this.altKey =  event.altKey;
        this.ctrlKey = event.ctrlKey;
        this.shitfKey = event.shitfKey;
        this.clientX = event.clientX;
        this.clientY = event.clientY;
        this.screenX = event.screenX;
        this.screenY = event.screenY;
        this.keyCode = event.keyCode;
           
        this.originaEvent = event;
        
    }
}

其中JCore.js文件見上一篇日誌“Javascript實現import動態導入文件方法”!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章