Chinaunix首页 | 论坛 | 博客
  • 博客访问: 485917
  • 博文数量: 55
  • 博客积分: 1867
  • 博客等级: 上尉
  • 技术积分: 587
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-29 01:33
文章分类

全部博文(55)

文章存档

2013年(1)

2012年(2)

2011年(16)

2010年(11)

2009年(5)

2008年(10)

2007年(8)

2006年(2)

分类:

2011-01-25 23:35:39

  前面有两篇文章提到了面向模型对象的编程和绑定DOM事件到业务对象,在实际的工作中,发现事件的浏览器兼容也是一件麻烦事,诸如srcElement, target, button等,网络上很多文章,大都只关注在局部,而缺乏一个统一的处理方法(也许是我的孤陋寡闻),所以想继续扩展一下上一篇文章《绑定DOM事件到对象》中的方法,为事件处理提供一个更通用的界面。
  既然是要贯彻面向对象的编程思想,自然要使用对象的方式来封装DOM事件,直觉的想象是有一个Event类,当DOM事件发生时,实例化这个类,然后事件处理程序直接这个Event对象,而没有浏览器差异。如下:

js.awt.Event = function(e){

    var _e = e || window.event;

    var ie = (_e.stopPropagation == undefined);
    
    this.event = _e;
    this.type = _e.type;
    this.timeStamp = new Date();

    this.altKey    = _e.altKey || false;
    this.ctrlKey   = _e.ctrlKey || false;
    this.shiftKey  = _e.shiftKey || false;
    this.metaKey = _e.metaKey || false;


    this.keyCode = ie ? _e.keyCode : _e.which;
    
    // left:1, right:2, middle:4
    switch(_e.button){
    case 0:
        this.button = 1;
        break;
    case 1:
        this.button = ie ? 1 : 4;
        break;
    default:
        this.button = _e.button;
        break;
    }

    this.clientX = ie ? (_e.clientX +
                         document.documentElement.scrollLeft -
                         document.body.clientLeft) : _e.pageX;
    this.clientY = ie ? (_e.clientY +
                         document.documentElement.scrollTop -
                         document.body.clientTop ) : _e.pageY;

    this.offsetX = ie ? _e.offsetX : _e.layerX;

    this.offsetY = ie ? _e.offsetY : _e.layerY;


    this.srcElement = ie ? _e.srcElement : _e.target;


    this.fromElement= ie ? _e.fromElement :
        ((this.type == "mouseover")? _e.relatedTarget :
         (this.type == "mouseout" ? _e.target : undefined));


    this.toElement = ie ? _e.toElement :
        ((this.type == "mouseout") ? _e.relatedTarget :
         (this.type == "mouseover" ? _e.target : undefined));

    this.cancelBubble = function(){
        if(_e.stopPropagation){
            _e.stopPropagation();
        }else{
            _e.cancelBubble = true;
        }
    };

    this.getEventXY = function(){
        return {x:this.clientX, y:this.clientY};
    };

};


何时实例化这个类呢,当然是在捕获事件之时,如下:

/**

 * @param thi$, the function runtime scope

 * @param isEventListener, whether the function is a DOM event handler

 * @param ..., other parameters need pass to this function

 */

Function.prototype.$bind = function(thi$, isEventListener) {
    var fn = this;
    var args = Array.prototype.slice.call(arguments, 2);
    fn.__handler__ = function(e) {
        var array = args;
        if(isEventListener){

            // 在这里实例化js.awt.Event
            array.unshift(new js.awt.Event(e));
        }
        return fn.apply(thi$, array);
    };


    return fn.__handler__;
};


上一篇文章中的attach, detach稍作一些修改,变成js.awt.Event的两个静态方法,如下:

/**
 * Attach event listener
 *
 * @param dom, event capture element
 * @param evType, such as "load","click" etc.
 * @param exclusive, true means dom.click = handler.
 * false means dom.attachEvent("onclick", handler)
 * @param thi$, the object of handler
 * @param handler
 * @param ..., other parameters need pass to handler
 */

js.awt.Event.attach = function(dom, evType, exclusive, thi$, handler){
    var args = Array.prototype.slice.call(arguments, 5);
    args.unshift(thi$, true);
    var _handler = handler.$bind.apply(handler, args);
    
    if(exclusive){
        dom["on"+evType] = _handler;
    }else{
        if(dom.addEventListener){
            dom.addEventListener(evType, _handler, false);
        }else{
            dom.attachEvent("on"+evType, _handler);
        }
    }

    return _handler;
};
/**
 * Detach event listener
 *
 * @see js.awt.Event.attach(dom, evType, exclusive, thi$, handler)
 */

js.awt.Event.detach = function(dom, evType, exclusive, thi$, handler){
    var _handler = handler.__handler__ || handler;
    
    if(exclusive){
        dom["on"+evType] = null;
    }else{
        if(dom.removeEventListener){
            dom.removeEventListener(evType, _handler, false);
        }else{
            dom.detachEvent("on"+evType, _handler);
        }
    }
};


还用Button的例子,看一下如何使用(以下代码在IE,FF,Chrome下测试过):


<html>
<head>
<script>
js = {awt:{}};

js.awt.Event = function(e){
    var _e = e || window.event;

    var ie = (_e.stopPropagation == undefined);
    
    this.event = _e;
    this.type = _e.type;
    this.timeStamp = new Date();

    this.altKey = _e.altKey || false;
    this.ctrlKey = _e.ctrlKey || false;
    this.shiftKey = _e.shiftKey || false;
    this.metaKey = _e.metaKey || false;

    this.keyCode = ie ? _e.keyCode : _e.which;
    
    // left:1, right:2, middle:4
    switch(_e.button){
    case 0:
        this.button = 1;
        break;
    case 1:
        this.button = ie ? 1 : 4;
        break;
    default:
        this.button = _e.button;
        break;
    }

    this.clientX = ie ? (_e.clientX +
                         document.documentElement.scrollLeft -
                         document.body.clientLeft) : _e.pageX;
    this.clientY = ie ? (_e.clientY +
                         document.documentElement.scrollTop -
                         document.body.clientTop ) : _e.pageY;

    this.offsetX = ie ? _e.offsetX : _e.layerX;
    this.offsetY = ie ? _e.offsetY : _e.layerY;

    this.srcElement = ie ? _e.srcElement : _e.target;

    this.fromElement= ie ? _e.fromElement :
        ((this.type == "mouseover")? _e.relatedTarget :
         (this.type == "mouseout" ? _e.target : undefined));

    this.toElement = ie ? _e.toElement :
        ((this.type == "mouseout") ? _e.relatedTarget :
         (this.type == "mouseover" ? _e.target : undefined));

    this.cancelBubble = function(){
        if(_e.stopPropagation){
            _e.stopPropagation();
        }else{
            _e.cancelBubble = true;
        }
    };

    this.getEventXY = function(){
        return {x:this.clientX, y:this.clientY};
    };

};

Function.prototype.$bind = function(thi$, isEventListener) {
    var fn = this;
    var args = Array.prototype.slice.call(arguments, 2);
    fn.__handler__ = function(e) {
        var array = args;
        if(isEventListener){
            // 在这里实例化js.awt.Event
            array.unshift(new js.awt.Event(e));
        }
        return fn.apply(thi$, array);
    };

    return fn.__handler__;
};

js.awt.Event.attach = function(dom, evType, exclusive, thi$, handler){
    var args = Array.prototype.slice.call(arguments, 5);
    args.unshift(thi$, true);
    var _handler = handler.$bind.apply(handler, args);
    
    if(exclusive){
        dom["on"+evType] = _handler;
    }else{
        if(dom.addEventListener){
            dom.addEventListener(evType, _handler, false);
        }else{
            dom.attachEvent("on"+evType, _handler);
        }
    }

    return _handler;
};

js.awt.Event.detach = function(dom, evType, exclusive, thi$, handler){
    var _handler = handler.__handler__ || handler;
    
    if(exclusive){
        dom["on"+evType] = null;
    }else{
        if(dom.removeEventListener){
            dom.removeEventListener(evType, _handler, false);
        }else{
            dom.detachEvent("on"+evType, _handler);
        }
    }
};


/////////////////////////////////////////////////////////////////////////////////////////////////////////////


//简单地定义一个Button类
js.awt.Button = function(def){
    this.view = document.createElement("div");
    this.view.id = def.id;
    this.view.style.cssText = "position:absolute;float:left;width:150px;height:20px;cursor:default;";
    this.view.style.backgroundColor = "gray";
    this.view.innerHTML = "Hello World";

    this.onmousedown = function(e){
        e.cancelBubble();
    };

    this.onclick = function(e){
        alert(e instanceof js.awt.Event);
    };

    this.onmousemove = function(e){
        this.view.innerHTML = e.offsetX + ", " + e.offsetY;
    };
    
    this.onmouseover = function(e){
        this.view.style.backgroundColor = "red";
        if(this.label != undefined){
            var t = "from:"+e.fromElement.id + "  to:"+e.toElement.id;
            this.label.setText(t);
        }
    };

    this.onmouseout = function(e){
        this.view.innerHTML = "Hello World";
        this.view.style.backgroundColor = "gray";
    };

    this.setPosition = function(x, y){
        this.view.style.left = x+"px";
        this.view.style.top = y+"px";
    };


    var _ = js.awt.Event;
    _.attach(this.view, "mousedown", false, this, this.onmousedown);
    _.attach(this.view, "mousemove", false, this, this.onmousemove);
    _.attach(this.view, "mouseover", false, this, this.onmouseover);
    _.attach(this.view, "mouseout", false, this, this.onmouseout);
    _.attach(this.view, "click", false, this, this.onclick);
};

//简单地定义一个Label类

js.awt.Label = function(def){
    this.view = document.createElement("span");
    
    this.setText = function(text){
        this.view.innerHTML = text;
    };
};


var onLoad = function(){
    var label = new js.awt.Label();
    document.body.appendChild(label.view);

    var button1 = new js.awt.Button({id:"btn1"});
    button1.setPosition(50, 50);
    button1.label = label;
    document.body.appendChild(button1.view);

    var button2 = new js.awt.Button({id:"btn2"});
    button2.setPosition(200, 50);
    button2.label = label;
    document.body.appendChild(button2.view);
    
};

js.awt.Event.attach(window, "load", true, window, onLoad);

</script>
</head>

<body>
</body>
</html>




阅读(1807) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~