事件&储存
对应知识点
1、通用事件绑定
<button id="btn1">这是一个按钮</button>
<div id="div1">
<a href="xxxxx" id="link1">这是个a标签</a>
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
// 通用事件绑定
var btn = document.getElementById('btn1')
btn.addEventListener('click', function (event) {
console.log('clicked')
})
// 封装通用事件绑定函数
function binEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
// 使用封装的 binEvent
var a = document.getElementById('link1')
binEvent(a, 'click', function (e) {
e.preventDefault() // 阻止默认行为
alert('clicked')
})
2、事件冒泡
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
// 事件冒泡
// 封装通用事件绑定函数
function binEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
/*
解析: div1 中的p2 至 p4 以及 div2 中的 p5 至 p6 都是取消,
所以可以把取消事件冒泡至 body 上, 只有p1 是激活,所有对p1单独触发事件
但是p1 也会向上冒泡,div1没有绑定事件,就会冒泡到body
body绑定了事件,当p1事件触发完了,会接着触发body上的事件
即 触发‘激活’之后,就会触发‘取消’
*/
var p1 = document.getElementById('p1')
var body = document.body
binEvent(p1, 'click', function (e) {
console.log(e)
e.stopPropagation() // 阻止冒泡
alert('激活')
})
binEvent(body, 'click', function (e) {
alert('取消')
})
3、代理
代理:该代理是指冒泡代理
<div id="div3">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
<!-- 会随时新增更多的 a 标签 -->
</div>
// 代理 该代理是指冒泡代理
/*
解析: 给多个标签绑定同一事件时,
可以通过冒泡到共同父级元素绑定该事件,
这样的好处是不用一个一个绑定
减少代码冗余
减少浏览器内存占用
*/
var div3 = document.getElementById('div3')
div3.addEventListener('click', function (e) {
var target = e.target // 确切当前点击的是哪个标签
if (target.nodeName === 'A') {
alert(target.innerHTML)
}
})
4、完善通用绑定事件函数 ------ 使用代理和不使用代理的情况
<p id="p1">激活</p>
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
<!-- 会随时新增更多的 a 标签 -->
</div>
// 完善通用绑定事件的函数
function binEvent(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) // 改变 this指向,this指向当前点击的元素上
}
} else {
// 不使用代理
fn(e)
}
})
}
// 使用代理
// div1 代理了 a 标签的绑定事件
var div1 = document.getElementById('div1')
binEvent(div1, 'click', 'a', function (e) {
console.log(this.innerHTML) // call 改变的 this this指向了a元素
})
// 不使用代理
var p = document.getElementById('p1')
binEvent(p, 'click', function (e) {
console.log(p.innerHTML)
})
对应面试题
1、编写一个通用的事件监听函数
function binEvent(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) // 改变 this指向,this指向当前点击的元素上
}
} else {
// 不使用代理
fn(e)
}
})
}
2、描述事件冒泡流程
(1)DOM树形结构
(2)事件冒泡
(3)阻止冒泡
(4)冒泡应用(代理,即绑定同一事件时,可以冒泡至共同父级绑定事件)
3、对于一个无限下拉加载图片的页面,如何给每个图片绑定事件
(1)使用代理 (即绑定同一事件时,可以冒泡至共同父级绑定事件)
(2)代理的两个优点
—> 减少代码冗余,使代码简洁
—> 减少浏览器内存占用