资讯专栏INFORMATION COLUMN

Event Handler 事件处理程序 2 ---跨浏览器事件对象《高程3》

roadtogeek / 2897人阅读

摘要:一旦事件处理程序执行完成,对象就会被销毁。所有浏览器对的支持方式包括事件对象和事件对象。无论指定事件处理程序时使用什么方法级或级,都会传入对象。由于不支持事件捕获,因而只能取消事件冒泡但可以同时取消事件捕获和冒泡。

0 Event Object导论

支持DOM0、DOM2的浏览器和IE浏览器实现事件处理程序的不同,除了体现在添加事件处理程序的不同上,还体现在event对象的实现差异上,包括具体的属性和方法。
在触发DOM上的某个事件时,都会产生一个event对象,这个对象包含着所有与事件有关的信息。一旦事件处理程序执行完成,event对象就会被销毁。所有浏览器对event的支持方式包括:DOM事件对象和IE事件对象。

1.1 DOM0和DOM2支持的Event对象(针对IE之外的浏览器)

兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0 级或 DOM2 级) ,都会传入 event 对象。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);

在通过 HTML 特性指定事件处理程序时,变量 event 中保存着 event 对象:


1.2 event对象常用属性和方法

(1) type, String; 只读; 被触发的事件的类型,如click。
(2) currentTarget, Element,只读,其事件处理程序当前正在处理事件的那个元素;
(3) target, Element, 只读, 事件的目标;
在事件处理程序内部,对象 this 始终等于 currentTarget 的值(注册事件处理程序的元素),而 target 则只包含事件的实际目标(事件直接触发的元素)。如果直接将事件处理程序指定给了目标元素,则 this、 currentTarget 和 target 包含相同的值。但是考虑到有时候会使用事件冒泡机制,事件直接触发的元素不一定是事件绑定的元素,例如:

 //按钮在body中,事件会冒泡到body
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};

当单击这个例子中的按钮时, this 和 currentTarget 都等于 document.body,因为事件处理程序是注册到这个元素上的。然而, target 元素却等于按钮元素,因为它是 click 事件真正的目标。由于按钮上并没有注册事件处理程序,结果 click 事件就冒泡到了 document.body,在那里事件才得到了处理。

(4) preventDefault()方法:阻止特定事件的默认行为。例如,链接的默认行为就是在被单击时会导航到其 href 特性指定的 URL。

var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};

(5) stopPropagation()方法:用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。这个属性在jQuery中很重要。

(6) eventPhase 属性:可以用来确定事件当前正位于事件流的哪个阶段。如果是在捕获阶段调用的事件处理程序,那么 eventPhase 等于 1;如果事件处理程序处于目标对象(直接点击对象,一般是最内层对象)上,则 eventPhase 等于 2;如果是在冒泡阶段调用的事件处理程序, eventPhase 等于 3。这里要注意的是,尽管“处于目标”发生在冒泡阶段,但 eventPhase 仍然一直等于 2。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.eventPhase); //2 ,最内元素在事件传播结束后触发
};
document.body.addEventListener("click", function(event){
alert(event.eventPhase); //1,DOM2事件触发使用true参数是在传播阶段触发
}, true);
document.body.onclick = function(event){
alert(event.eventPhase); //3,DOM0事件在冒泡阶段触发
};

当单击这个例子中的按钮时,首先执行的事件处理程序是在捕获阶段触发的添加到 document.body中的那一个,结果会弹出一个警告框显示表示 eventPhase 的 1。接着,会触发在按钮上注册的事件处理程序,此时的 eventPhase 值为 2。最后一个被触发的事件处理程序,是在冒泡阶段执行的添加到document.body 上的那一个,显示 eventPhase 的值为 3。而当 eventPhase 等于 2 时,this、target和 currentTarget 始终都是相等的。

2.1 IE中的事件对象

IE中event对象的访问方式取决于绑定事件处理程序的方法:
1)DOM0级方法: event对象作为window对象的一个属性存在。

        var btn = document.getElementById("myBtn");
        btn.onclick = function(){
        var event = window.event;
            alert(event.type); //"click"
        };

2)如果事件处理程序是通过attachEvent()添加的,就有一个event对象作为事件处理程序的参数。

    

        var btn = document.getElementById("myBtn");
        alert(typeof attachEvent);
        btn. attachEvent("click", function(event){
            alert(event.type); //"click"
        });
2.2 IE中event对象的属性和方法

1)cancelBubble:默认值为false,但将其设置为true就可以取消事件冒泡(与DOM中
的stopPropagation()方法的作用相同);
2)returnValue:默认值为true,但将其设置为false就可以取消事件的默认行为(与
DOM中的preventDefault()方法的作用相同);
3)srcElement:事件的直接目标(与DOM中的target属性相同);
4)type:被触发的事件的类型。

srcElement:因为事件处理程序的作用域是根据指定它的方式来确定的, this 不一定总是等于事件目标。例如:

var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(window.event.srcElement === this); //DOM0级方法,true
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});

returnValue 属性:只要将 returnValue 设置为 false,就可以阻止默认行为。

var link = document.getElementById("myLink");
link.onclick = function(){
window.event.returnValue = false;
};

cancelBubble 属性:与 DOM 中的 stopPropagation()方法作用相同,都是用来停止事件冒泡的。由于 IE 不支持事件捕获,因而只能取消事件冒泡;但 stopPropagatioin()可以同时取消事件捕获和冒泡。例如:

//在单击按钮之后,只会显示一个警告框。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
window.event.cancelBubble = true;
};
document.body.onclick = function(){
alert("Body clicked");
};
2.3 IE11的变化

但是在IE11发布之后attachEvent函数被替换成了addEventListener。

var btn = document.getElementById("myBtn");
alert(typeof addEventListener);//function
btn.addEventListener("click", function(event){
    alert(event.type); //"click"
});

IE11中srcElement属性测试:

HTML:

the onlt one div

JavaScript:

    var wrapper = document.getElementById("wrapper");
    alert(typeof addEventListener);
    wrapper.addEventListener("click", function(event){
        alert(event.target); //span
        alert(event.currentTarget); //div
        alert(event.srcElement); //span
        alert(this);//div
    });

结论:srcElement和target是相同的,都指向事件的直接元素,但是this和currentTarget都指向事件绑定元素。

如果需要阻止默认行为,直接使用在addEventListener()中使用event.preventDefault()即可。根据以上,可以得出初步的结论:在IE11浏览器中使用addEventListener()后,DOM2级event具有的属性和方法都可以使用。

我在IE中使用addEventListener()并没有遇到问题,但是网上有一些开发者在使用时会遇到问题,提供的解决方法有数种:
https://social.msdn.microsoft...
第一种是加入一些脚本:

    

第二种是把IE的internet选项-- >安全,点击“将所有区域重置为默认级别”。

3 跨浏览器的事件对象EventUtil
    var EventUtil = {
        //是否支持DOM2?是否是IE?是否支持DOM0?一般前两个if包含了所有情况
        addHandler: function(element, type, handler){
            if (element.addEventListener){
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent){
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }
        },
        //IE没有event对象,因此使用window.event
        getEvent: function(event){
            return event ? event : window.event;
        },
        /*使用getEvent()方法得到event对象后才可以使用getTarget()、
        preventDefault()、stopPropagation()方法
        */
        //先检测DOM0 DOM2的target属性,然后检测IE的srcElement属性
        getTarget: function(event){
            return event.target || event.srcElement;
        },
        //先检测DOM0 DOM2的preventDefault(),再检测IE的returnValue
        preventDefault: function(event){
            if (event.preventDefault){
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },
        //是否支持DOM2?是否是IE?是否支持DOM0?一般前两个if包含了所有情况
        removeHandler: function(element, type, handler){
            if (element.removeEventListener){
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent){
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }
        },
        //先检测DOM0 DOM2的stopPropagation(),再检测IE的cancelBubble
        stopPropagation: function(event){
            if (event.stopPropagation){
                event.stopPropagation();
            } else {
                event.cancelBubble = true;
            }
        }
    };

测试实例:

    var but = document.getElementById("myButtun");
    var handler = function(event){
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
         alert(target);// [object HTMLInputElement]
        
    };
    EventUtil.addHandler(but, "click", handler);

当然,上述跨浏览器的事件对象所包含的属性和方法并不是必须的,在实际中可以根据实际情况适当删减一些属性和方法。但是,万变不离其宗。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/50143.html

相关文章

  • Make a simple custom EventEmitter

    Thoughts Recently I have been reading the book Async Javascript about JS asynchronicity and JS event is one of the useful solutions to the problem. To get a deeper understanding of how events work, I ...

    fizz 评论0 收藏0
  • php微框架 flight源码阅读——2.框架初始化、Loader、Dispatcher

    摘要:当调用时,会触发当前类的魔术方法,通过判断属性中索引是否存在,不存在抛出异常,存在就通过去实例化初始化时设置的,这里是工厂模式,接下来的路由文章会详细分析。在操作中,会将前置操作设置到类的属性中。微框架源码阅读系列 在自动加载实现完成后,接着new flightEngine()自动加载的方式实例化了下框架的核心类Engine,这个类名翻译过来就是引擎发动机的意思,是flight的引擎发...

    U2FsdGVkX1x 评论0 收藏0
  • Vue.js 表格组件

    //Vue组件开始 var Grid = Vue.extend({ template: {{col.display}} ...

    Alliot 评论0 收藏0
  • 使用 Authing + Lambda 替代 AWS Cognito

    摘要:编写函数编写函数推荐使用这个,控制台中的函数编写堪称让人痛不欲生。在控制台中安装在中引入包后会一起打包上传到运行时中。 Amazon Web Services(AWS) 虽然作为市场份额全球第一的云计算厂商,其产品也不是完美无缺的,Cognito (AWS 的身份认证解决方案)及其附带的中文文档就是一个反面教材,其难用程度令人发指。当然,除了不易用之外,还有访问速度缓慢,不适用于中国市...

    Vultr 评论0 收藏0
  • Image Load Error Handler

    Preface In the past, I posted an answer in SO about how to replace broken images. And the code is window.addEventListener( error, windowErrorCb, { capture: true }, true ) function windo...

    cocopeak 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<