DOM事件与事件委托
3.自定义事件
- 浏览器自带事件
一共100多种时间,列表在MDN上:事件参考 - 提问
开发者能不能在自带事件之外,自定义一个事件
答:可以
- 自定义事件
创建一个 名称为 frank ,可以自动冒泡,但是不能阻止冒泡的自定义事件
<div id=div1>
<button id=button1>点击触发 frank 事件
</button>
</div>
button1.addEventListener('click', () => { //被点击时触发一个自定义事件
const event = new CustomEvent('frank', {
detail: {name: 'frank',age: 18},
bubbles: true, //可以冒泡,也就是可以通过监听div1获得事件信息
cancelable: false //不能阻止冒泡
}) //创建一个自定义事件,告诉事件名和详细信息
button1.dispatchEvent(event) //button1就触发事件
})
div1.addEventListener('frank', (e) => {
console.log('frank事件触发了')
console.log(e.detail)
})
3.事件委托
- 委托:委托中介做本该自己做的事情
- 事件委托:委托一个元素帮我监听我本该监听的东西
- 场景一
1.你要给100个按钮添加点击事件,咋办?
答:监听这100个按钮的祖先,等冒泡的时候判断 target 是不是这 100 个按钮中的一个 - 场景二
你要监听目前不存在的元素的点击事件,咋办?
答:监听祖先,等点击的时候看看是不是我想要监听的元素即可 - 优点
1.省监听数(内存)
2.可以监听动态元素:后面才会出现的元素
3.1 场景一代码
- 将监听绑在div1上,判断以下被点击的是谁即可
- tagName 属性返回元素的标签名。
- toLowerCase() 方法用于把字符串转换为小写。
- 如何知道点击的是 div1 中的哪一个button?
答:通过被点击的元素 - data-id 和 id的区别
1.id是选择器
2.data-id只是行内存放数据的一个标签
3.同时在HTML5 中增加了一项新功能是 自定义数据属性 ,也就是 data-* 自定义属性。
4.在HTML5中我们可以使用以 data- 为前缀来设置我们需要的自定义属性,来进行一些数据的存放。 - dataset 可以获取以data开头的属性的值
<div id="div1">
<span>span1</span>
<button data-id='1'>click1</button>
<button data-id='2'>click2</button>
<button data-id='3'>click3</button>
</div>
div1.addEventListener('click',(e)=>{
const t = e.target //被用户点击的元素
if(t.tagName.toLowerCase()==='button'){//如果被点击的元素是button,说明是button元素中的一个
console.log('button 被点击了')
// console.log('buuton内容是'+t.textContent)
console.log('button data-id是'+t.dataset.id)
}
})
3.2 场景二代码
- 一秒之后出现button
- 动态元素
<div id="div1">
</div>
setTimeout(()=>{
const button = document.createElement('button')
button.textContent = 'click1'
div1.appendChild(button)
},1000)
div1.addEventListener('click',(e)=>{
const t = e.target
if(t.tagName.toLowerCase()==='button'){
console.log('button 被 click了')
}
})
4.封装事件委托
- 上面是针对特定场景的事件委托
- 写一个函数,用户只需要用这个on事件,就可以在 div1上面做事件委托,来看button有没有被点击
- 输入:接收四个参数,事件类型、元素(被委托的)、选择器(准备匹配什么元素)、函数(点击的时候被调用的)
- matches 用来判断一个元素是否满足一个选择器(比如:一个元素是不是 li、button)
- 这个函数就是一个封装好的事件委托函数,只要用这个 on,就可以实现事件委托
<div id="div1">
</div>
setTimeout(()=>{
const button = document.createElement('button')
button.textContent = 'click1'
div1.appendChild(button)
},1000)
on('click','#div1','button',()=>{
console.log('button 被点击了')
})
function on(eventType,element,selector,fn){
if(!(element instanceof Element)){
element = document.querySelector(element)
}//如果element不是元素,则寻找这个元素
element.addEventListener(eventType,(e)=>{
const t = e.target
if(t.matches(selector)){
fn(e)
}
})
}
5.面试:什么是事件委托
- 给元素添加一个监听,然后看当前的 target 是否满足 selector,如果满足就调用函数,如果不满足就放过
- 但这个方法是有问题的
1.如果文字外面有个span,那么用户点击的就是 span
2.那么我们在匹配的时候 span 就不匹配 button,无法实现事件监听
3.解决:使用递归判断,如果当前元素不匹配,就依次往外走,判断target、target的爸爸、target的爷爷,一直到div1停止
<div id="div1">
<button>
<span>文字</span>
</button>
</div>
6.JS支持事件吗?
- 答
支持,也不支持。本节课讲的是 DOM 事件不属于 JS 的功能,术语浏览器提供的 DOM功能
JS是浏览器的功能之一,DOM事件又是浏览器的另一个功能
JS只是调用了 DOM 提供的 addEventListener 这个API而已 - 能否手写出一个 JS事件系统
用一个队列,后面在思考