JavaScript基础——事件

事件是将JavaScript与网页联系在一起的主要方式。"DOM3级事件"规范和HTML5定义了常见的大多数事件。

即使有规范定义了基本事件,但多数浏览器仍然在规范之外实现了自己的专有事件,从而为开发人员提供更多掌握用户

交互的手段。有些专有事件与特定设备关联,例如移动Safari中的orientationchange事件就是特定关联ios设备的。

在使用事件时,需要考虑如下一些内存与性能方面的问题。

1)有必要限制一个页面中事件处理程序的数量,数量太多会导致占用大量内存,而且也会让用户感觉页面反应不够灵敏。

2)建立在事件冒泡机制至上的事件委托技术,可以有效地减少事件处理程序的数量。

3)建议在浏览器卸载页面之前移除页面中的所有事件处理程序。

可以使用JavaScript在浏览器中模拟事件。"DOM2级事件"和"DOM3级事件"规范规定了模拟事件的方法,为模拟各种有定义的事件提供了方便。此外,通过组合使用一些技术,还可以在某种程度上模拟键盘事件。IE8及之前版本同样支持事件模拟,只不过模拟的过程有些诧异。

事件是JavaScript中最重要的主题之一,深入理解事件的工作机制以及它们对性能的影响至关重要。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件</title>
</head>
<body>
<button id="myBtn">DOM0级事件处理程序</button>
<button id="myBtn2">DOM2级事件处理程序</button>
<button id="myBtn3">IE事件处理程序</button>
<button id="myBtn4">跨浏览器的事件处理程序</button>
<button id="myBtn5">DOM中的事件对象</button>
<button id="myBtn6">处理多个事件</button>
<a href="www.baidu.com" id="myLink">阻止默认行为</a>
<button id="myBtn7">取消事件的冒泡或捕获</button>
<button id="myBtn8">测试事件位于事件流的哪个阶段</button>
<input type="text" id="myText"/>
<div id="myDiv" style="width: 300px;height: 300px;border: 1px solid red"></div>
<ul id="myMenu" style="position: absolute;visibility: hidden;background-color: silver">
    <li><a href="http://www.baidu.com">百度</a></li>
    <li><a href="http://www.sina.com.cn">新浪</a></li>
    <li><a href="http://www.qq.com">腾讯</a></li>
</ul>
<ul id="myLinks">
    <li id="goSomewhere">去哪儿</li>
    <li id="doSomething">做什么</li>
    <li id="sayHi">你好</li>
</ul>
<div id="myDiv2">
    <input type="button" value="点我" id="clickMe"/>
</div>
<button id="myBtn9">模拟鼠标事件</button>
<script src="l13.js"></script>
</body>
</html>
/*
 * 事件
 */
function cl(x){
    console.log(x);
}
/**
 * 13.1 事件流
 */
//13.1.1 事件冒泡
//IE的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。

//13.1.2 事件捕获(很少使用)
//事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。

//13.1.3 DOM事件流
//"DOM2级事件"规定的事件流包括:事件捕获阶段、处于目标阶段和事件冒泡阶段。

/**
 * 13.2 事件处理程序
 */
//13.2.1 HTML事件处理程序(要摒弃)

//13.2.2 DOM0级事件处理程序
var btn=document.getElementById("myBtn");
btn.οnclick=function(){
    cl(this.id);//=>"myBtn"
}
btn.οnclick=null;//删除事件处理程序

//13.2.3 DOM2级事件处理程序 (IE9+)
var btn2=document.getElementById("myBtn2");
var handler=function(){
    cl(this.id);//=>"myBtn2"
}
btn2.addEventListener("click",handler,false);
btn2.addEventListener("click",function(){//可添加多个事件
    cl("hello world");//=>"hello world"
},false);
btn2.removeEventListener("click",handler,false);//移除事件

//13.2.4 IE事件处理程序
//var btn3=document.getElementById("myBtn3");
//var handler2=function(){
//    cl(this===window);
//};
//btn3.attachEvent("onclick",handler2);
//btn3.detachEvent("onclick",handler2);

//13.2.5 跨浏览器的事件处理程序
var EventUtil={
    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;
        }
    },
    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;
        }
    }
};
var btn4=document.getElementById("myBtn4");
var handler4=function(){
    cl("跨浏览器处理事件程序");//=>"跨浏览器处理事件程序"
};
EventUtil.addHandler(btn4,"click",handler4);
EventUtil.removeHandler(btn4,"click",handler4);

/**
 * 13.3 事件对象
 */
//13.3.1 DOM中的事件对象
    //event对象
var btn5=document.getElementById("myBtn5");
btn5.οnclick=function(event){
    cl(event.type);//=>"click"
}
btn5.addEventListener("click",function(event){
    cl(event.type);//=>"click"
},false);
//注意event.currentTarget与event.target的区别
btn5.addEventListener("click",function(event){
    cl(event.currentTarget===this);//=>true
    cl(event.target===this);//=>true
});
document.body.οnclick=function(event){
    cl(event.currentTarget===document.body);//=>true
    cl(this===document.body);//=>true
    cl(event.target===document.getElementById("myBtn5"));//=>true
}
var btn6=document.getElementById("myBtn6");
var handler6=function(event){
    switch(event.type){
        case "click":
            cl("点击事件");
            break;
        case "mouseover":
            event.target.style.backgroundColor="red";
            break;
        case "mouseout":
            event.target.style.backgroundColor="";
            break;
    }
};
btn6.οnclick=handler6;
btn6.οnmοuseοver=handler6;
btn6.οnmοuseοut=handler6;
//阻止特定事件的默认行为:preventDefault()方法
var link=document.getElementById("myLink");
link.οnclick=function(event){
    event.preventDefault();
}
//stopPropagation()方法用于立即停止事件在DOM层次中的传播
var btn7=document.getElementById("myBtn7");
btn7.οnclick=function(event){
    cl("Click");
    event.stopPropagation();
}
document.body.οnclick=function(event){
    cl("Body click");
}
//事件对象的eventPhase属性,用来确定事件当前正位于事件流的哪个阶段
//捕获=1,目标=2,冒泡=3
var btn8=document.getElementById("myBtn8");
btn8.οnclick=function(event){
    cl(event.eventPhase);//=>2
}
document.body.addEventListener("click",function(event){
    cl(event.eventPhase);//=>1
},true);
document.body.οnclick=function(event){
    cl(event.eventPhase);//=>3
}

//13.3.2 IE中的事件对象
//DOM0级时:event=window.event
//DOM2级时:event对象与DOM中相同
//srcElement与DOM中target相同
//event.returnValue设置为false来阻止默认行为
//event.cancelBubble设置为true来取消事件冒泡

//13.3.3 跨浏览器的事件对象
var EventUtil={
    //添加事件监听
    addHandler:function(element,type,handler){
        if(element.addEventListener){
            element.addEventListener(type,handler,false);//w3c
        }else if(element.attachEvent){
            element.attachEvent("on"+type,handler);//IE
        }else{
            element["on"+type]=handler;//低版本浏览器
        }
    },
    //获取事件元素
    getEvent:function(event){
        return event?event:window.event;
    },
    //获取事件目标
    getTarget:function(event){
        return event.target||event.srcElement;
    },
    //阻止默认事件
    preventDefault:function(event){
        if(event.preventDefault){
            event.preventDefault();//W3C
        }else{
            event.returnValue=false;//IE
        }
    },
    //移除事件监听
    removeHandler:function(element,type,handler){
        if(element.removeEventListener){
            element.removeEventListener(type,handler,false);//W3C
        }else if(element.detachEvent){
            element.detachEvent("on"+type,handler);//IE
        }else{
            element["on"+type]=null;//低版本浏览器
        }
    },
    //阻止冒泡
    stopPropagation:function(event){
        if(event.stopPropagation){
            event.stopPropagation();//W3C
        }else{
            event.cancelBubble=true;//IE
        }
    },
    //相关元素属性
    getRelatedTarget:function(event){
        if(event.relatedTarget){
            return event.relatedTarget;
        }else if(event.toElement){
            return event.toElement;
        }else if(event.fromElement){
            return event.fromElement;
        }else{
            return null;
        }
    },
    //获取鼠标按钮属性
    getButton:function(event){
        if(document.implementation.hasFeature("MouseEvents","2.0")){
            return event.button;
        }else{//IE8及以下
            switch (event.button){
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    },
    //获取鼠标滚轮事件属性
    getWheelDelta:function(event){
        if(event.wheelDelta){
            return (client.engine.opera && client.engine.opera<9.5 ?
                -event.wheelDelta:event.wheelDelta);
        }else{
            return -event.detail*40;
        }
    },
    //获取字符编码属性
    getCharCode:function(event){
        if(typeof event.charCode=="number"){
            return event.charCode;
        }else{
            return event.keyCode;
        }
    }
};

/**
 * 13.4 事件类型
 */
//13.4.1 UI事件
//load、unload、abort、error、select、resize、scroll
//13.4.1.1 load事件
//当页面完全加载后(包含所有图像、JavaScript文件、CSS文件等外部资源)触发window上面的load事件
EventUtil.addHandler(window,"load",function(event){
    cl("文档加载完成");
});
EventUtil.addHandler(window,"load",function(event){
    var image=document.createElement("img");
    EventUtil.addHandler(image,'load',function(event){
        event=EventUtil.getEvent(event);
        cl(EventUtil.getTarget(event).src);
    });
    document.body.appendChild(image);
    //image.src="about_2.jpg";
});

EventUtil.addHandler(window,'load',function(){
    var image=new Image();
    EventUtil.addHandler(image,'load',function(event){
        cl("图片加载完毕");
    });
    image.src="head.jpg";
});
//13.4.1.2 unload事件
//文档被完全卸载后触发,利用这个事件最多的情况是清除引用,以避免内存泄露
EventUtil.addHandler(window,'unload',function(event){
    cl("页面卸载了");
});
//13.4.1.3 resize事件
//当浏览器窗口被调整到一个新的高度或宽度时,就会触发resize事件
EventUtil.addHandler(window,'resize',function(event){
   cl("窗口大小改变了");
});
//13.4.1.4 scroll事件
//当用户滚动带滚动条的元素中的内容时,在该元素上面触发
EventUtil.addHandler(window,'scroll',function(event){
    if(document.compatMode=="CSS1Compat"){
        cl(document.documentElement.scrollTop);
    }else{
        cl(document.body.scrollTop);
    }
});

//13.4.2 焦点事件
//blur、focus、focusin、focusout

//13.4.3 鼠标与滚轮事件
//click、dbclick、mousedown、mouseenter、mouseleave、mousemove、mouseout、mouseover、mouseup
//13.4.3.1 客户区坐标位置
//13.4.3.2 页面坐标位置
//13.4.3.3 屏幕坐标位置
var div=document.getElementById("myDiv");
EventUtil.addHandler(div,'click',function(event){
    event=EventUtil.getEvent(event);
    cl("点击的视口位置:"+event.clientX+","+event.clientY);
    cl("点击的页面位置:"+event.pageX+","+event.pageY);
    cl("点击的屏幕位置:"+event.screenX+","+event.screenY);
});
//13.4.3.4 修改键
//shiftKey、ctrlKey、altKey和metaKey
EventUtil.addHandler(div,'click',function(event){
    event=EventUtil.getEvent(event);
    var keys=new Array();
    if(event.shiftKey){
        keys.push("shift");
    }
    if(event.ctrlKey){
        keys.push("ctrl");
    }
    if(event.altKey){
        keys.push("alt");
    }
    if(event.metaKey){
        keys.push("meta");
    }
    cl("Keys:"+keys.join(","));
});
//13.4.3.5 相关元素
//relatedTarget属性,只对于mouseover和mouseout事件才包含值
var div=document.getElementById("myDiv");
EventUtil.addHandler(div,"mouseout",function(event){
    event=EventUtil.getEvent(event);
    var target=EventUtil.getTarget(event);
    var relatedTarget=EventUtil.getRelatedTarget(event);
    cl("鼠标从 "+target.tagName+ "移到了"+relatedTarget.tagName);
});
//13.4.3.6 鼠标按钮
var div=document.getElementById("myDiv");
EventUtil.addHandler(div,"mousedown",function(event){
    event=EventUtil.getEvent(event);
    cl(EventUtil.getButton(event));
});
//13.4.3.7 更多的事件信息
//detail属性
//13.4.3.8 鼠标滚轮事件
//mousewheel事件 DOMMouseScroll事件
(function(){
    function handleMouseWheel(event){
        event=EventUtil.getEvent(event);
        var delta=EventUtil.getWheelDelta(event);
        cl(delta);
    }
    EventUtil.addHandler(document,"mousewheel",handleMouseWheel);
    EventUtil.addHandler(document,"DOMMouseScroll",handleMouseWheel);
})();
//13.4.3.9 触摸设备
//13.4.3.10 无障碍性问题

//13.4.4 键盘与文本事件
//keydown事件、keypress事件、keyup事件、textInput事件
//13.4.4.1 键码:keyCode属性
var textBox=document.getElementById("myText");
EventUtil.addHandler(textBox,"keyup",function(event){
    event=EventUtil.getEvent(event);
    cl(event.keyCode);
});
//13.4.4.2 字符编码:charCode属性
var textBox=document.getElementById("myText");
EventUtil.addHandler(textBox,"keypress",function(event){
    event=EventUtil.getEvent(event);
    cl(EventUtil.getCharCode(event));
});
//13.4.4.3 DOM3级变化
//存在浏览器兼容性问题
//13.4.4.4 textInput事件
var textBox=document.getElementById("myText");
EventUtil.addHandler(textBox,"textInput",function(event){
    event=EventUtil.getEvent(event);
    cl(event.data);
});
//13.4.4.5 设备中的键盘事件

//13.4.5 复合事件(IE9+支持)
//compositionstart事件、compositionupdate事件、compositionend事件
var textBox=document.getElementById("myText");
var isSupported=document.implementation.hasFeature("CompositionEvent","3.0");
if(isSupported){//IE9+
    EventUtil.addHandler(textBox,"compositionstart",function(event){
        event=EventUtil.getEvent(event);
        cl(event.data);
    });
    EventUtil.addHandler(textBox,"compositionupdate",function(event){
        event=EventUtil.getEvent(event);
        cl(event.data);
    });
    EventUtil.addHandler(textBox,"compositionend",function(event){
        event=EventUtil.getEvent(event);
        cl(event.data);
    });
}else{
    cl("该浏览器不支持复合事件");
}
//13.4.6 变动事件
//DOMSubtreeModified、DOMNodeInserted、DOMNodeRemoved
var isSupported=document.implementation.hasFeature("MutationEvents","2.0");
//13.4.6.1删除节点
//13.4.6.2插入节点

//13.4.7 HTML5事件
//13.4.7.1 contextmenu事件:上下文菜单
EventUtil.addHandler(window,"load",function(event){
    var div=document.getElementById("myDiv");
    EventUtil.addHandler(div,"contextmenu",function(event){
        event=EventUtil.getEvent(event);
        EventUtil.preventDefault(event);
        var menu=document.getElementById("myMenu");
        menu.style.left=event.clientX+"px";
        menu.style.top=event.clientY+"px";
        menu.style.visibility="visible";
    });
    EventUtil.addHandler(document,"click",function(event){
        document.getElementById("myMenu").style.visibility="hidden";
    })
});
//13.4.7.2 beforeunload事件:卸载页面前
EventUtil.addHandler(window,"beforeunload",function(event){
    event=EventUtil.getEvent(event);
    var message="真的要卸载吗?";
    event.returnValue=message;
    return message;
})
//13.4.7.3 DOMContentLoaded事件:DOM树加载之后触发
EventUtil.addHandler(document,"DOMContentLoaded",function(event){
    cl("内容加载完成");
});
//13.4.7.4 readystatechange事件
EventUtil.addHandler(window,"load",function(){
    var script=document.createElement("script");
    EventUtil.addHandler(script,"readystatechage",function(event){
        event=EventUtil.getEvent(event);
        var target=EventUtil.getTarget(event);
        if(target.readyState=="loaded" || target.readyState=="complete"){
            EventUtil.removeHandler(target,"readystatechange",arguments.callee);
            cl("script加载完成");
        }
    });
    script.src="example.js";
    document.body.appendChild(script);
})
//13.4.7.5 pageshow和pagehide事件
(function(){
    var showCount=0;
    EventUtil.addHandler(window,"load",function(){
        cl("Load fired");
    });
    EventUtil.addHandler(window,"pageshow",function(){
        showCount++;
        cl("Show has been fired "+showCount+" times");
    })
})();
//13.4.7.6 hashchange事件
EventUtil.addHandler(window,"hashchangge",function(event){
    cl("准确的hash:"+location.hash);
})
//13.4.8 设备事件
//13.4.8.1 orientationchange事件
EventUtil.addHandler(window,"load",function(event){
    var div=document.getElementById("myDiv");
    div.innerHTML="现在的方向是"+window.orientation;
    EventUtil.addHandler(window,"orientationchange",function(event){
        div.innerHTML="现在的方向是"+window.orientation;
    })
})
//13.4.8.2 mozOrientation事件
//13.4.8.3 deviceorientation事件
EventUtil.addHandler(window,"deviceorientation",function(event){
    var output=document.getElementById("output");
    output.innerHTML="Alpha="+event.alpha+",Beta="+event.beta+",Gamma="+event.gamma+"<br/>";
});
EventUtil.addHandler(window,"deviceorientation",function(event){
    var arrow=document.getElementById("arrow");
    arrow.style.webkitTransform="rotate("+Math.round(event.alpha)+"deg)";
});
//13.4.8.4 devicemotion事件
EventUtil.addHandler(window,"devicemotion",function(event){
    var output=document.getElementById("output");
    if(event.rotationRate!==null){
        output.innerHTML="Alpha="+event.rotationRate.alpha+",Beta="+event.rotationRate.beta+",Gamma="+event.rotationRate.gamma+"<br/>";
    }
})
//13.4.9 触摸与手势事件
//13.4.9.1 触摸事件
//13.4.9.2 手势事件
//gesturestart、gesturechange、gestureend

/**
 * 13.5 内存和性能
 */
//13.5.1 事件委托
var list=document.getElementById("myLinks");
EventUtil.addHandler(list,"click",function(event){
    event=EventUtil.getEvent(event);
    var target=EventUtil.getTarget(event);
    switch(target.id){
        case "doSomething":
            document.title="我改了标题";
            break;
        case "goSomewhere":
            location.href="http://www.baidu.com";
            break;
        case "sayHi":
            cl("hi");
            break;
    }
});
//13.5.2 移除事件处理程序
var btn=document.getElementById("clickMe");
btn.οnclick=function(){
    //先执行某些操作
    btn.οnclick=null;
    document.getElementById("myDiv2").innerHTML="Processing...";
}

/**
 * 13.6 模拟事件
 */
//13.6.1 DOM中的事件模拟
//13.6.1.1 模拟鼠标事件
var btn9=document.getElementById("myBtn9");
//创建事件对象
var event=document.createEvent("MouseEvents");
//初始化事件对象
event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
//触发事件
btn9.dispatchEvent(event);
//13.6.1.2 模拟键盘事件
//13.6.1.3 模拟其他事件
//13.6.1.4 自定义DOM事件
var div=document.getElementById("myDiv"),event;
EventUtil.addHandler(div,"myevent",function(event){
    cl("DIV: "+event.detail);
});
EventUtil.addHandler(document,"myevent",function(event){
    cl("DOCUMENT: "+event.detail);
});
if(document.implementation.hasFeature("CustomEvents","3.0")){
    event=document.createEvent("CustomEvent");
    event.initCustomEvent("myevent",true,false,"hello world!");
    div.dispatchEvent(event);
}

//13.6.2 IE中的事件模拟



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值