40 DOM事件与事件委托

1 捕获和冒泡

2002年,W3C发布标准

文档名为DOM Level 2 Events Specification

规定浏览器应该同时支持两种调用顺序

首先按 爷爷 => 爸爸 => 儿子 顺序看有没有函数监听

然后按 儿子 => 爸爸 => 爷爷 顺序看有没有函数监听

有监听函数就调用,并提供事件信息,没有就跳过

事件绑定API

IE5 *:baba.attachEvent('onclick',fn) //冒泡

网景:baba.addEventListener('click',fn) //捕获

W3C:baba.addEventListener('click',fn,boolean)   ==>>>> W3C标准

如果boolean不传值或者为falsy

就让fn走冒泡,即当浏览器在冒泡阶段发现baba 有fn监听函数,就会调用fn ,并提供事件信息

如果boolean为true

就让fn走捕获,即当前浏览器在捕获阶段发现baba有fn监听函数,就会调用fn,并提供事件信息

术语

从外向内找监听函数,叫事件捕获

从内向外找监听函数,叫事件冒泡   

实例链接  => 先捕获  后冒泡

2  target VS currentTarget

e.target - 用户操作的元素

e.currentTarget - 程序员监听的元素

this 是e.currentTarget,不推荐使用(因为用this你不知道你获取的是target 还是currentTarget )  =>>>>  在事件监听中 不推荐使用this

举个例子

div > span{文字}   当用户点击文字 =>>>>看下面理解

e.target就是span

e.currentTarget就是div

一个特例

背景

只有一个div被监听(不考虑父子同时被监听)

fn分别在捕获阶段和冒泡阶段监听click事件

用户点击的元素就是开发者监听的

代码

div.addEventLisenter('click',f1)   两行中 谁放在前面一行(第一行)谁就先执行 (也就是谁先监听谁先执行)

div.addEventLisenter('click',fn,true)

请问,f1先执行还是f2先执行? =>>>>>>>>>   谁先监听谁先执行

如果把两行调换位置后,请问哪个先执行? =>>>>>>>>  谁先监听谁先执行

3 取消冒泡  

    =>>捕获不可取消,但冒泡可以

e.stopPropagetion() 可中断冒泡,浏览器不再向上走

一般用于封装某些独立的组件

4 不可阻止默认动作

    有些事件不能阻止默认动作

MDN 搜索srcoll event,看到Bubbles 和 Cancelable

Bubbles的意思是该事件是否冒泡,所有冒泡都可取消

Cancelable的意思是开发者是否可以阻止默认事件

Cancelable与冒泡无关

推荐看mnd英文版 中文版本内容不全

5 如何阻止滚动

scroll事件不可阻止默认动作

阻止scroll默认动作没用,因先有滚动才有滚动事件

要阻止滚动,可阻止wheel和touchstart的默认动作

注意你需要找准滚动条所有的元素

但是滚动条还能用,可用css让滚动条width:0

2 --来自几人谷教学图

css也行

使用overflow:hidden可以直接取消滚动条

但此时JS依然可以修改scrollTop

6 自定义事件

各种默认事件链接

以下代码是如何自定义一个事件

const button = document.querySelector('.button1')

button.addEventListener('click',()=>{    

const event = new CustomEvent('lulu',{        

detail{name:'frank',age:'18'},        //设置内容

bubbles:true , //是否取消冒泡        

composed:false //是否阻止冒泡 不阻止

})    

div1.dispatchEvent(event)})div.addEventListener('lulu',(e)=>{     

//div1为div标签id=div1

console.log(e.detail)

})


自定义事件

7 事件委托

事件委托:我委托一个人 帮我干本来我该干的事情

     ====>>>>> 小记 案例用到的一些方法

1  js字母大小写转换方法

        转换成大写:toUpperCase()

        转换成小写:toLowerCase()

2  tagName  获取标签名

    e.target.tagName  获取用户点击的标签名

    e.currentTarget.tagName  获取程序员点击事件的标签名

3 e.target.dataset.id   具体可看下图1

      获取html内容 data-id='1' 里面的1

21313

4 e.target.textContent 

    获取当前用户操作标签点击按钮的内容21313 

21313

图1

第一小节 100个按钮 怎么省内存监听

实例代码

box.addEventListener('click',(e)=>{   

    const t = e.target    // console.log(t)    

    if(t.tagName.toLowerCase() === 'button'){      

        console.log('button被点击了,我的内容是:'+ t.textContent)    //获取button上面展示的内容 如下图2

        console.log('被点击了 ,我获取的内容是 标签上的data-id= ' + t.dataset.id) //图3图解

     }      

 })    


事件委托 图2


事件委托图3

第二小节 怎么监听暂时不存在(后面动态生成或者是setTimeout(1000s)执行)的元素

上代码

// 获取暂时不存在的元素

setTimeout(()=>{    

const button= document.createElement('button')   

 button.textContent = '我是button内容'    

// console.log(button)        

box.appendChild(button) //注意点 写的时候写错了 前面是父元素 后面是要添加的子元素

},1000)

box.addEventListener('click',(e)=>{    

const t = e.target    

if(t.tagName.toLowerCase()==='button'){             

console.log('被点击')    

}})   

第三小节 封装事件委托

要求:

写出这样一个函数on('click','#testDiv','li',fn)

当用户点击#testDiv里面的li远不时,调用fn函数

要求用到事件委托

代码

setTimeout(()=>{   

 const button = document.createElement('button')    

button.textContent = '我是动态1000s后button里面的内容'    

box.appendChild(button)},1000)

on('click','#box','button',()=>{    

console.log('元素被点击了')})

function on(eventType,element,selector,fn){   

 if(!(element instanceof Element)){ //   判断一个元素是不是真正的元素 判断它是不是对象也可以用它  instanceof Object   判断数组 instanof Array

element = document.querySelector(element)   

 }    

element.addEventListener(eventType,(e)=>{     

const t = e.target       

 if(t.matches(selector)){     //matches 判断它是不是一个选择器

       fn(e)       

 }        

 } 

)}        


封装委托事件图解

代码二:高级版 (给button里面的span加点击 代码一 不能实现点击)

setTimeout(()=>{    

const button = document.createElement('button')    

const span = document.createElement('span')    

span.textContent = '我是动态1000s后span里面的内容'    

box.appendChild(button)   

 button.appendChild(span)},1000)

on('click','#box','button',()=>{     

console.log('button 被点击了')})

function on(eventType,element,selector,fn){    

if(!(element instanceof Element)){            

 element = document.querySelector(element)    }    

element.addEventListener(eventType,(e)=>{       

 let t = e.target        

while(!t.matches(selector)){            

if(element === t){             

t = null               

break            

}             

t = t.parentNode               

 }       

 t && fn.call(t,e,t)   

 })    

 return element      

}     

JS支持事件吗?

答:

支持 也不支持   以上案例写的DOM事件不属于JS功能,术语浏览器提供的DOM功能

JS只是调用了DOM提供的addEventListener()而已

你可能感兴趣的:(40 DOM事件与事件委托)