js事件绑定模型
为HTML元素添加事件属性
//html
<button onclick="func()">按钮</button>
//script
function func() {
//...
}
function funb() {
//...
}
<button onclick="func()" onclick="funb()">按钮</button>
//绑定两个onclick事件,只会触发前一个
<button onclick="func(),funb()">按钮</button>
//一个onclick事件绑定两个方法,两个方法都会被触发
通过js选取DOM节点,添加该节点的事件属性
//HTML
<button id="btn1">按钮</button>
//script
document.getElementById("btn1").onclick=func
document.getElementById("btn1").onclick=funb
//同时绑定两个事件,只能触发最后的一个(funb)
优点:使js代码与HTML标签分离,文档结构清晰,便于管理和开发
**缺点:**同一个节点只能添加一次同类型事件,如果添加多次,最后一个生效;一旦绑定无法取消
用 addEventListener()
或 attachEvent()
来绑定事件监听函数。
element.addEventListener(event, function, useCapture)
element.attachEvent(eventName,handle)
element
:指定元素
addEventListener()
方法用于向指定元素添加事件
event
:指定事件名,不需要on
前缀
function
:事件触发执行的函数
useCapture
:指定事件是否在捕获或冒泡阶段执行(true
:捕获;false
(默认):冒泡)
//HTML
<button id="btn1">按钮</button>
//script
document.getElementById("btn1").addEventListener("click",func)
document.getElementById("btn1").addEventListener("click",funb)
//两个事件都能触发,顺序是func -> funb
document.getElementById("btn1").attachEvent("onclick",func)
document.getElementById("btn1").attachEvent("onclick",funb)
//触发顺序funb -> func
//移除事件
document.getElementById("btn1").removeEventListener("click",func)
addEventListener
和attachEvent
的区别addEventListener
是从上到下,attachEvent
从下到上addEventListener
可以选择是否使用捕获addEvntListener
是标准的绑定事件监听函数方法,但在IE8.0及其以下版本不支持,需使用attachEvent
。所以使用这种绑定事件的方法需要处理浏览器兼容问题。处理方法如下:
function addEvent(obj,type,handle){
try{
// Chrome、FireFox、Opera、Safari、IE9.0及其以上版本
obj.addEventListener(type,handle,false);
}catch(e){
try{
// IE8.0及其以下版本
obj.attachEvent('on' + type,handle);
}catch(e){
// 早期浏览器
obj['on' + type] = handle;
}
}
}
优点:
(1)同一个节点可以绑定多个同类型事件;
(2)可以使用removeEventListener
和detachevent
取消事件绑定
事件的捕获与冒泡(js中的事件流模型)
事件:与浏览器或文档交互的瞬间,比如点击按钮、填写表格等,是HTML与JS之间交互的桥梁。
事件流:DOM是树形结构,同时给父节点和子节点绑定事件,当触发子节点的时候,这两个事件的发生顺序就是事件流决定的。描述的是页面中接受事件的顺序。
IE提出的,像水冒泡一样从下往上传播的方式。事件从子节点逐渐向上传播到父节点。
网景公司提出的,与冒泡相反。事件从父节点开始逐渐深入向子节点传播。
DOM2级事件做了一个比较折中的规范。规定的事件流包含3个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
首先发生事件捕获到达实际的目标,实际目标接收事件,最后一个阶段是从实际目标开始冒泡,在这个阶段对事件做出响应。
使用addEventListener
进行事件绑定的时候,第三个参数默认为false,设置事件在冒泡阶段进行。
//HTML
<div class="red">
<div class="green">
<div class="yellow"></div>
</div>
</div>
//script
function funa() {
console.log('a')
}
function funb() {
console.log('b')
}
function func() {
console.log('c')
}
document.getElementsByClassName("red")[0].addEventListener("click",funa)
document.getElementsByClassName("green")[0].addEventListener("click",funb)
document.getElementsByClassName("yellow")[0].addEventListener("click",func)
//执行顺序:c->b->a,在冒泡阶段进行事件
当第三个参数为true,设置在捕获阶段执行的时候
document.getElementsByClassName("red")[0].addEventListener("click",funa,true)
document.getElementsByClassName("green")[0].addEventListener("click",funb,true)
document.getElementsByClassName("yellow")[0].addEventListener("click",func,true)
//执行顺序:a->b->c,在捕获阶段进行事件
document.getElementsByClassName("red")[0].addEventListener("click",funa,true)
document.getElementsByClassName("green")[0].addEventListener("click",funb)
document.getElementsByClassName("yellow")[0].addEventListener("click",func,true)
//执行顺序:a->c->b,a和c在捕获阶段进行,b在冒泡阶段进行
如果事件是在捕获阶段进行的,那么阻值冒泡依然会进行
function myParagraphEventHandler(e) {
e = e || window.event;
if (e.stopPropagation) {
e.stopPropagation(); //IE10以后
console.log('stopPropagation')
} else {
e.cancelBubble = true; //IE10之前
console.log('cancelBubble')
}
}
//script
function funa() {
console.log('a')
}
function funb() {
//myParagraphEventHandler() 事件c,b会触发,事件a被截止
console.log('b')
}
function func() {
//myParagraphEventHandler() 事件c会被触发,事件a,b被冒泡截止
console.log('c')
}
前面讲到了事件冒泡,子元素身上的事件会冒泡到父元素身上。而事件代理是:本来加在子元素身上的事件,加在了其父级身上。
window.event.srcElement
,其他浏览器是event.target
使用事件委托之前:
//html
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
//js
window.onload = function(){
var oUl = document.getElementById('ul1');
var aLi = oUl.children;
for (var i=0;i<aLi.length;i++) {
aLi[i].onmouseover = function() {
this.style.background = 'red';
}
aLi[i].onmouseout = function(){
this.style.background = '';
}
}//for结束
}
使用事件代理:
window.onload = function(){
var oUl = document.getElementById('ul1');
oUl.onmouseover = function(ev){
var ev = ev || window.event;
var oLi = ev.srcElement || ev.target;
if(oLi.nodeName.toLowerCase() == 'li'){
//判断点击的是不是li元素,防止点击整个ul的时候触发事件
Li.style.background = 'red';
}
}
oUl.onmouseout = function(ev){
var ev = ev || window.event;
var oLi = ev.srcElement || ev.target;
if(oLi.nodeName.toLowerCase() == 'li'){
oLi.style.background = '';
}
}
}
event.currentTarget
和event.target
currentTarget
:表示此事件绑定的元素,比如绑定的ultarget
:通俗理解为表示触发一系列事件的源头,比如点击的li