DOM事件与事件委托

DOM事件

DOM事件包括100多种,包括点击事件等。这些事件能够事件捕获和事件冒泡,事件捕获的特色是从外到内监听函数,即从父亲到儿子;事件冒泡的特色是从内到外监听函数,即从儿子到父亲。程序员能够决定使用事件捕获仍是事件冒泡。程序员

程序员如何决定捕获仍是冒泡

捕获事件web

元素.addEventListener('click',fn,不传参或者falsy)
复制代码

冒泡事件浏览器

元素.addEventListener('click',fn,true)
复制代码

题外话

CSS:给class属性以level开头的每个div元素bash

div[class^=level]{
    //添加CSS属性
}
复制代码

实例:使用冒泡事件监听click

level1.addEventListener('click',(e)=>{
   //将传入对象e暂存
   const t=e.currentTarget
   setTimeout(()=>{
       //点击时去掉自身的.x
       t.classList.remove('x')
   },n*1000)
   n+=1
},true)
复制代码

函数的结构:fn里面有3个函数,第一个是将参数e暂存,为何须要暂存:由于e只存在点击的一瞬间,执行setTimeout里面时,e已经消失,不会执行;第二个参数是1秒后再执行;第三个是将n加1,不至于全部的闹钟一块儿响app

捕获事件和冒泡事件如何一块儿作

level1.addEventListener('click',(e)=>{
    //将参数e暂存
    const t=e.currentTarget
    setTimeout(()=>{
        //点击时将自身的.x去掉
    t.classList.remove('x')
    },n*1000)
    n+=1
},true)

level1.addEventListener('click',(e)=>{
    //将参数e暂存
    const t=e.currentTarget
    setTimeout(()=>{
        //点击时将自身的.x去掉
    t.classList.add('x')
    },n*1000)
    n+=1
},false)
复制代码

target与cruurentTarget的区别

  • e.target——用户操做的元素
  • e.currentTarget——程序员监听的元素
  • this指向e.currentTarget,因为很差记,不推荐使用this

举例:

<div>
 <span>文字</span>
</div>
复制代码
当用户点击了文字,e.target就是span,e.currentTarget就是div
复制代码

捕获、冒泡的前后顺序

W3C的事件模型:先捕获(先爸爸后儿子),再冒泡(先儿子再爸爸)。注意,e对象传给全部监听函数,监听事件结束后,能够认为e对象不存在。函数

特例

当用户操做的元素就是开发者监听的元素,fn分别在捕获阶段和冒泡阶段监听click事件ui

div.addEventListener('click',f1)    //捕获事件
div.addEventListener('click',f2,true)  //冒泡事件
复制代码

请问,先执行哪一个事件? 谁先监听,就先执行哪一个this

如何取消冒泡及冒泡属性

捕获事件不能取消,可是冒泡能够取消。e.stopPropagation()能够中断冒泡,浏览器再也不往上走,通常用于封装某些独立的组件,Bubbles属性是该事件是否冒泡,Cancelable的属性是开发者是否能够取消冒泡spa

如何阻止页面滚动

<div id="x">
  ………………
</div>
复制代码

第一:阻止滚轮滚动code

x.addEventListener("wheel",
 (e)=>{
     e.preventDefault()
 }
)
复制代码

第二:阻止鼠标滚动,设置CSS

::-webkit-scrollbar{
    width:0 !improtant
}
复制代码

第三:阻止手机的触屏滚动

x.addEventListener('touchstart',
  (e)=>{
      e.preventDefault()
  }
)
复制代码

自定义DOM事件:自定义一个frank事件,而且能冒泡,可是不能阻止冒泡

HTML:

<div id="div1">
       <button id="button1">
         点击触发frank事件
       </button>
    </div>
复制代码

JavaScript:

button1.addEventListener('click',()=>{
   //声明自定义事件
   const event = new CustomEvent('frank',{
   //自定义事件的信息
   detail:{name:'frank',age:18},
   //能够冒泡
   bubbles:true,
   //不能阻止冒泡
   cancelable:false
   })
   //让button1触发事件,至关于调用
   button1.dispatchEvent(event)
}))

//监听button1
button1.addEventListener('frank',(e)=>{
   console.log(e.detail)
})
复制代码

事件委托

特定情景一

<div id="div1">
  …………中间有100个button标签
</div>
复制代码

请问,若是给100个button标签添加点击事件,怎么作?
思路:监听它们的祖先元素div,等冒泡的时候判断target是否是这100个按钮中的一个。
作法:

div1.addEventListener('click',(e)=>{
   const t=e.target
   if(t.tagName.toLowerCase()=== 'button'){
       console.log('button 被点击了')
       console.log('button内容是'+t.textContent)
   }
})
复制代码

体现出事件委托的优势:省监听数(省内存)

特定情景二

若是监听目前不存在的元素的点击事件,怎么作?
思路:监听祖先元素,等点击的时候看看是否是我想要监听的元素。
作法:

//1秒钟以后,在div里面建立button
setTimeout(()=>{
   //建立button按钮
   const button=document.createElement('button')
   //button按钮里面文本
   button.textContent='click 1'
   //向div1里面添加子节点button
   div1.appendChild(button)
},1000)

//监听button元素1秒钟以后是否被用户点击
div1.addEventListener('click',(e)=>{
    //获取用户操做的元素
   const t=e.target
   if(t.tagName.toLowerCase() === 'button'){
       console.log('button 被click')
   }
})
复制代码

体现出事件委托的优势:能够动态监听元素

封装一个事件委托:事件委托就是监听祖先元素,等咱们点击时来判断它是否是咱们要监听的元素,是的话执行函数

用户只须要经过on事件,监听div下面的button是否被点击

on('click','#div1','button',()=>{
    console.log('button被点击了')
})

function on(eventType,element,selector,fn){
    //若是element不是一个元素,就获取element所在的元素
    if(!(element instanceof Element)){
        element=document.querySelector(element)
    }
    
    element.addEventListener(eventType,(e)=>{
        const t=e.target
        //matches判断一个元素是否知足一个选择器
        if(t.matches(selector)){
            fn(e)
        }
    })
}
复制代码

注意

上面的事件委托是DOM事件,DOM是由浏览器提供的,JS只是调用了DOM提供的addEventListener。

相关文章
相关标签/搜索