事件监听器(事件绑定、事件侦听)
一个元素对象上面可以绑定多个事件处理函数,事件监听分为:标准浏览器事件监听、IE浏览器事件监听(非标准浏览器事件监听)
/*
标准浏览器事件监听
target.addEventListener("事件类型", 函数, 是否捕获(布尔值))
是否捕获:默认不写就是冒泡(false) , true:捕获
*/
document.addEventListener('click', function () {
console.log('事件绑定1');
}, false);
document.addEventListener('click', function () {
console.log('事件绑定2');
}, false);
/*
IE浏览器事件监听
target.attachEvent("事件类型",函数)
*/
document.attachEvent('onclick', function() {
alert('事件绑定1');
});
document.attachEvent('onclick', function() {
alert('事件绑定2');
});
事件绑定:标准浏览器和非标准浏览器的区别
1.参数不一样。标准的三个参数,非标准的二个参数
2.事件类型不一样。标准不带on
3.执行顺序不一样。
4.this指向不一样,标准浏览器事件处理函数里面的this当前的操作的元素,但是非标准浏览器的this指向window
兼容解决事件绑定
function addEvent(obj, etype, fn) {
if (obj.addEventListener) { //标准
obj.addEventListener(etype, fn, false);
} else {
obj.attachEvent('on' + etype, fn);
}
}
function fn1() {
alert('兼容处理事件绑定1');
}
function fn2() {
alert('兼容处理事件绑定2');
}
addEvent(document, 'click', fn1);
addEvent(document, 'click', fn2);
取消事件监听:参数和事件绑定的参数是一致的
target.removeEventListener()--标准浏览器取消监听
target.detachEvent() --IE浏览器取消监听
function removeEvent(obj, etype, fn) {
if (obj.addEventListener) { //标准
obj.removeEventListener(etype, fn, false);
} else {
obj.detachEvent('on' + etype, fn);
}
}
removeEvent(document, 'click', fn1);
//取消事件绑定,不能取消匿名函数。
事件捕获
事件的第一个阶段是捕获阶段;事件从文档的根节点流向目标对象节点;途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达事件的目标节点;捕获阶段的主要任务是建立传播路径,在冒泡阶段,事件会通过这个路径回溯到文档跟节点。
<div class="big">
<div class="middle">
<div class="small"></div>
</div>
</div>
比如上图的代码,三个div标签呈嵌套关系,假使三个元素都注册了相同的事件,那么他们的触发顺序是怎样的呢?
<script src="./JS2004.js"></script>
<script>
//微软(microsoft) - 冒泡
//网景(netscape) 捕获
var small = $('.small');
var middle = $('.middle');
var big = $('.big');
function fn() { //事件处理函数
console.log(this.className);
}
function addEvent(obj, etype, fn, bool) {
if (obj.addEventListener) { //标准
obj.addEventListener(etype, fn, bool); //false:冒泡
} else {
obj.attachEvent('on' + etype, fn);
}
}
//事件冒泡
addEvent(small, 'click', fn, true); //目标
addEvent(middle, 'click', fn, false);
addEvent(big, 'click', fn, true);
addEvent(document.body, 'click', fn, false);
addEvent(document.documentElement, 'click', fn, true);
addEvent(document, 'click', function () {
console.log('我是document');
}, false);
</script>
结果如下:
事件委托:
事件委托:利用了冒泡原理,将子元素的事件委托给父元素
ev.target:获取当前操作的目标元素对象 标准的
ev.srcElement:获取当前操作的目标元素对象 非标准的
使用下方案例说明事件委托:
HTML代码:
<body>
<input type="text"><br>
<button>创建li元素</button>
<ul id="list">
</ul>
</body>
CSS代码:
ul {
margin: 0px;
padding: 0px;
}
li {
list-style: none;
width: 600px;
line-height: 24px;
border: 1px dashed #ccc;
padding: 10px;
margin-top: 10px;
}
JS代码:
<script>
var oBtn = document.querySelector('button');
var oText = document.querySelector('input');
var oUl = document.querySelector('ul');
//结构。
oBtn.onclick = function () {
var cLi = document.createElement('li');
cLi.innerHTML = oText.value + '<a href="javascript:;">删除</a>';
oUl.appendChild(cLi);
oText.value = '';
}
//删除的逻辑 - 事件委托
oUl.onclick = function (ev) {
var ev = ev || window.event;
var ele = ev.target || ev.srcElement; //获取当前操作的目标元素对象。
if (ele.nodeName === 'A') {
oUl.removeChild(ele.parentNode);
}
}
</script>
事件委托的优缺点:
1.优点:减少事件注册,节约内存,提升性能
比如:如果不采用事件委托,内部的子元素采用遍历的方式逐个添加事件。 添加父元素解决这个问题。
2.缺点:所有事件都用事件代理,可能会出现事件误判。即本不该被触发的事件被绑定上了事件。
比如:将所有的事件都绑定在document上面,所有的document内部的子元素事件都有可能触发到document上面。
事件冒泡需要时间类型一致