事件总括
* 1、行为本身:浏览器天生就赋予其行为onclick onmouseover onmouseout (onmouseenter onmouseleave不会产生事件冒泡) onmousemove
* onmousedown onmouseup onmousewheel onscroll onresize onload onunload onfocus onblur onkeydown onkeyup。。。
* 没有给上述行为绑定方法,事件也存在,触发后执行,只是什么都不做而已
* 2、事件绑定:
* oDiv.onclick=function... DOM0级事件绑定 onclick行为定义在oDiv的私有属性上
* oDiv.addEventListener('click',function(){},false) DOM2级事件 addEventListener这个属性是定义在EventTarget
* 这个类的原型上
事件的传播机制
* 捕获阶段:从里往外一次查找元素
* 目标阶段:当前事件源本身操作
* 冒泡阶段:从内到外依次触发相关行为(最常用)
- 冒泡和捕获
捕获就是:爹(target)的事件触发,儿子和孙子的相同的事件也会被触发
冒泡就是:儿子(target)触发事件,爹和祖宗的相同的事件也会被触发
阻止冒泡
e.stopPropagation会阻止冒泡,意思就是到我为止,我的爹和祖宗的事件就不要触发了。
事件委托
把事件绑定到目标元素群的父元素上,通过e.target来判断点击的真正目标,在执行相应的程序
事件冒泡与默认行为
让事件处理函数return false来阻止冒泡和默认行为, 可以认为return false做了三件事情:
1.stopPropagation();
2.preventDefault();
3.立即结束当前函数并返回。
DOM 0级事件
- 给元素对象的某一个私有的属性赋一个值(一个函数的值),当事件触发的时候找到对应的属性值,并且执行
- DOM 0级事件只能给元素的某一个事件绑定一次方法,最后绑定的方法会把前面绑定的所有的方法都覆盖掉
DOM 2级事件
- 给当前元素的某一个事件绑定的方法都放置在事件池中,当事件执行的时候,会把事件池里的所有的方法依次去执行
1.addEventListener 绑定事件
2.removeEventListener 移除事件 - DOM 2级事件可以为当前元素的某一个事件绑定多个不同的方法,当前事件触发时,会到对应的事件池中把所有的绑定的方法依次执行。
- DOM2和DOM0事件共存,不会冲突 。
深入
- DOM2可以给元素的某一个事件行为绑定多个方法
1.事件触发时执行对应的方法们,此时不管哪个方法中的this指向的都是当前元素
2.我们按顺序把顺序增加到‘事件池’中,当触发事件时,方法按照添加的顺序依次执行
3.如果当前的方法已经给元素的这个行为绑定过一次了,事件池中这个方法不会重复添加 - DOM2中,我们一般绑定的都是实名函数,只有这样,当移除的时候才知道移除谁,
在IE6-8中绑定的方法只能在冒泡阶段发生。 - DOM2事件在IE6-8中兼容问题。
1.绑定的语法不一样,IE6-8中,使用attachEvent、detachEvent
2.标准浏览器this指向当前元素,IE6-8指向window
3.重复绑定问题,IE6-8 相同的方法可以重复绑定
4.顺序问题,标准浏览器按绑定的顺序执行函数,IE6-8 没有顺序
function on(ele,type,fn){
if(/^self/.test(type)){//说明是自定义的事件 都带前缀self
if(!ele['aself'+type]){
ele['aself'+type]=[]//创建自定义事件的事件池
}
var a=ele['aself'+type];
for(var i=0;i<a.length;i++){
if(a[i]==fn)return;
}
a.push(fn);//如果这个函数没有添加过事件池,那么就添加进去
}else if(ele.addEventListener){//标准浏览器的事件添加
ele.addEventListener(type,fn,false);
}else{//IE浏览器的事件添加
if(!ele['aEvent'+type]){
ele['aEvent'+type]=[];
}
var a=ele['aEvent'+type];
for(var i=0;i< a.length;i++){
if(a[i]==fn)return;
ele.attach('on'+type,function(){//提前绑定好事件,只要触发就执行run
run.call(ele);
})
}
a.push(fn);
}
}
function run (){
var e=e||window.event;
if(!e.target){
e.target=e.srcElement;
e.pageX=e.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft);
e.pageY= e.clientY+(document.documentElement.scrollTop||document.body.scrollTop)
}
e.stopPropagation=function(){
e.cancelBubble=true;
}
e.preventDefault=function(){
e.returnValue=false
}
var a= this['aEvent'+type];
if(a){
for(var i=0;i< a.length;i++){
var fn=a[i];
if(type fn == 'function'){
fn.call(this,e);
}else{
a.splice(i,1)
i--;
}
}
}
}
function selfRun(selfType,e){
var a=this['aSelf'+selfType];
if(a){
for(var i=0;i< a.length;i++){
var fn=a[i];
if(type fn == 'function'){
fn.call(this,e);
}else{
a.splice(i,1)
i--;
}
}
}
}
function off(ele,type,fn){
if(/^self/.test(type)){
var a=ele['aSelf'+type];
if(a){
for(var i=0;i< a.length;i++){
if(a[i]==fn){
a[i]=null;
return;
}
}
}
}
if(ele.removeEventListener){
ele.removeEventListener(type,fn,false);
}else{
var a=ele['aEvent'+type]
if(a){
for(var i=0;i< a.length;i++){
if(a[i]==fn){
a[i]=null;
return;
}
}
}
}
}
自定义事件(订阅发布模式)
function EventEmitter(){
}
EventEmitter.prototype.on=function(type,fn){
if(!this['aEmitter'+type]){
this['aEmitter'+type]=[]
}
var a=this['aEmitter'+type];
for(var i=0i<a.length;i++){
if(a[i]==fn)return;
a.push(fn);
}
}
EventEmitter.prototype.run=function(type,e){
var a=this['aEmitter'+type];
if(a){
for(var i=0i<a.length;i++){
if(typeof a[i]=='function'){
a[i].call(this,e);
}else{
a.split(i,1);
i--;
};
}
}
}
EventEmitter.prototype.off=function(type,fn){
var a=this['aEmitter'+type];
if(a){
for(var i=0i<a.length;i++){
if(a[i]==fn){
a[i]=null;
};
}
}
}
jquery绑定
$(ele).bind() ------在新版本已经淘汰
将会给所有匹配的元素都绑定一次事件,当元素很多时性能会变差。 而且后来动态新增的元素不会被绑定。
可以添加自定义事件 然后用trigger来手动触发该事件。
多个事件类型可以通过用空格隔开一次性绑定:
$('#foo').bind('mouseenter mouseleave', function() {
$(this).toggleClass('entered');
});
- 可以通过传递一个事件类型/处理函数的数据键值对映射来绑定多个事件处理程序
$('#foo').bind({
click: function() {
// do something on click
},
mouseenter: function() {
// do something on mouseenter
}
});
$(ele).delegate()
- 它将事件处理函数绑定在指定的根元素上, 由于事件会冒泡,它用来处理指定的子元素上的事件。
- 用于事件委托。
$("table").delegate("td", "click", function() {
$(this).toggleClass("chosen");
});
是等价于下面使用.on()的代码:
$("table").on("click", "td", function() {
$(this).toggleClass("chosen");
});
$(ele).on()
- 绑定事件最通用的方法,用$(ele).off()解绑事件
- 向事件处理函数中传入数据,并且在事件处理函数中通过名字来获取传入的数据:
function myHandler(event) {
alert(event.data.foo);
}
$("p").on("click", {foo: "bar"}, myHandler)
$(ele).one()
- 处理函数在每个元素上每种事件类型最多执行一次
$( "#foo" ).one( "click", function() {
alert( "这个函数只会执行一次" );
});
- 如果该方法的第一个参数包含多个用空格分隔的事件类型的话,那么每种类型的事件被触发时,处理函数仅会被每个事件类型调用一次。
$( "#foo" ).one( "click mouseover", function( event ) {
alert( "The " + event.type + " event happened!" );
});
$(ele).trigger()
- 用来触发事件
$('#foo').on('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');//相当于用户点击了该元素
- 若要触发通过 jQuery 绑定的事件处理函数,而不触发原生的事件,使用
.triggerHandler()
来代替。