1、通用事件绑定
var btn = document.getElementById('btn1');
btn.addEventListener('click',function (event) {
console.log('clicked');
})
//
function bindEvent(elem,type,fn) {
elem.addEventListener(type,fn);
}
var a = document.getElementById('');
bindEvent(a,'click',function (e) {
e.preventDefault(); //阻止默认行为(<a>标签跳转)
alert('clicked');
})
2、IE低版本的兼容性
- IE低版本使用attachEvent绑定事件,和W3C标准不一样
- IE低版本使用量非常少,很多网站都早已不支持
3、事件冒泡
事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件。相反的,事件冒泡是自下而上的去触发事件。绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获。true,事件捕获;false,事件冒泡。默认false,即事件冒泡。
Jquery的e.stopPropagation会阻止冒泡。
4、代理——事件代理,即事件委托
(1)为什么要有事件代理?
一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;
每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了,比如上面的100个li,就要占用100个内存空间。如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,自然性能就会更好。
(2)事件委托的原理:
事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件。
举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。
- 通过事件冒泡机制
- 上层绑定,通过target属性来找真实触发的元素
如:<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
JS:window.onload = function () {
var ul = document.getElementById('ul1');
ul.onclick = function (e) {
var e = e || window.event;
var target = e.target || e.srcElement; //兼容IE
if(target.nodeName.toLowerCase() == "li"){
alert(target.innerHTML);
}
}
}
如:为新增节点添加事件
<input type="button" name="" id="btn" value="添加" />
<ul id="ul2">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
JS: var oBtn = document.getElementById('btn');
var oUl = document.getElementById('ul2');
var aLi = oUl.getElementsByTagName('li');
var num = 4;
//事件委托,添加的子元素也有事件
oUl.onmousemove = function (e) {
var e = e || window.event;
var target = e.target || e.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = "red";
}
};
oUl.onmouseout = function (e) {
var e = e || window.event;
var target = e.target || e.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = "#fff";
}
};
//添加新节点
oBtn.onclick = function () {
num++;
var oLi = document.createElement('li');
oLi.innerHTML = "新增节点" + num;
oUl.appendChild(oLi);
}
(3)代理的好处:
- 代码简洁
- 减少浏览器内存占用
解答:
1、编写一个通用的事件监听函数
function bindEvent(elem,type,selector,fn) {
if(fn == null){
fn = selector;
selector = null;
}
elem.addEventListener(type,function (e) {
var target;
if(selector){ //使用代理
target = e.target;
if(target.matches(selector)){
fn.call(target,e)
}
}else{ //不使用代理
fn(e);
}
})
}
//使用代理
var div1 = document.getElementById('');
bindEvent(div1,'click','a',function (e) {
console.log(this.innerHTML);
})
//不使用代理
var a = document.getElementById('');
bindEvent(div1,'click',function (e) {
console.log(a.innerHTML);
})
2、简述事件冒泡的流程。
- DOM树形结构
- 事件冒泡
- 阻止冒泡——preventDefault()
- 冒泡的应用——代理
3、无线下拉加载图片的页面,绑定事件——对滚动事件监听
使用代理
懒加载