DOM事件

DOM事件

  • 事件:用户或浏览器自身执行的某种动作。
    诸如click(点击)、load(加载)、mouseover(鼠标悬停)。
  • 事件处理程序:要在某个事件发生时,调用指定的函数,对事件作出相应的反应
    image

事件模型

D0M级模型(传统模型(Traditional Model)/统注册模型(Traditional Registration Model)

只能注册一个时间处理程序
<!-- HTML --><button>单击我</button>// Script
let handler1 = function () {
    console.log('Handler1:', this)
}

let handler2 = function () {
    console.log('Handler2', this)
}

document.querySelector('button'). = handler1
document.querySelector('button'). = handler2
//点击button按钮只会输出hander2()函数的结果

DOM Level 2模型:W3C标准事件模型,且不支持低于IE9的浏览器

- 事件捕获阶段(Capturing Phase):-->
- 事件处理阶段(Target Phase)
- 事件冒泡阶段(Bubbling Phase):<--

image

  • Q1:在DOM2模型中如何添加事件
    element.addEventListener(event, function, useCapture)
    useCapture(添加事件句柄的阶段):
    true-->事件句柄在捕获阶段执行
    false/空 默认-->事件句柄在冒泡阶段执行
document.querySelector('button').addEventListener('click',handle1,true)
document.querySelector('button').addEventListener('click',handle2,true)
////点击button按钮会同时输出hander1() hander2()函数的结果
  • Q2:在DOM2模型中如何移除事件
    element.removeEventListener(event, function, useCapture)
    useCapture(移除事件句柄的阶段):
    true-->事件句柄在捕获阶段被移除
    false/空 默认-->事件句柄在冒泡阶段被移除
let btn = document.getElementById('btn');
btn.addEventListener('click', handler, false);btn.removeEventListener('click', handler, false);
  • Q3:target 与currentTarget
    div>span{文字},用户点击文字
    target: 用户操作的元素,此处就是span
    currentTarget: 程序监听的元素,此处就是div
    其他:this是e.currentTarget,不推荐使用

  • Q4:如何取消冒泡
    e.stopPropagation()

事件特性

  • bubbles
  • cancelble
    image

事件委托

事件委托就是由祖先元素监听事件,并根据事件来源统一处理。

  • 场景一:给100个按钮添加点击事件
    A:监听100个的按钮的祖先元素,等冒泡的时候判断target(用户操作的元素)是不是这100个按钮中的元素,是就执行监听事件

  • 场景二:监听当年不存在的元素的点击事件
    A:监听祖先元素,点击时判断元素是否为目标元素

  • 场景三:

<div class="grandpa">
      <div class="father">
            <div class="child">
              <span class="text">文字</span>
            </div>
      </div>
</div>

对儿子元素(.child)进行 click 事件监听,当该元素被点击时,在控制台输出 我是子元素,我被点击了! 。

  • A1
const grandpaEl = document.getElementsByClassName('grandpa')[0];
grandpaEl.addEventListener('click', (e)=>{
      const el = e.target;
      if(el.className === 'child'){
            console.log('我被点击了!');
      }
})
//

当点击 .child 元素时会正确输出,
但当点击 .child 里面的 .text 元素时不会正确输出。
根据实际需求,当点击父元素包裹的子元素时,也是相当于点击了父元素,应当触发对应的事件处理函数
因此此种方法严格来说是错误的。
此种方法只适用于被监听的元素没有后代元素时使用。
  • A2:递归
const grandpaEl = document.getElementsByClassName('grandpa')[0];
grandpaEl.addEventListener('click', (e) => {
    let el = e.target;
    while (!el.matches('.child')) {
        if (el === grandpaEl) {
            el = null;
            break;
        }
        el = el.parentNode;
    }
    if (el) {
        console.log('我被点击了!');
    }
})
  • A3:事件对象的path属性
const grandpaEl = document.getElementsByClassName('grandpa')[0];
grandpaEl.addEventListener('click', (e)=>{
     let child = e.path.find(el => el.matches('.child'));
     if(child){
           console.log('我被点击了!');
     }
})

image

  • 事件委托优点
    ① 省监听数,省内存
    ② 可以监听动态元素

封装事件委托

前述场景三A2进行封装

function delegate(agent, eventType, clientSelector, fn){
      agent.addEventListener(eventType, (e)=>{
            let el = e.target;
            while(!el.matches(clientSelector)){
                  if(el === agent){
                        el === null;
                        break;
                  }
                  el = el.parentNode;
            }
            el && fn.call(el, e, el);
      })
      return agent;
}

部分学习搬运自
https://www.cnblogs.com/lovevin/p/13411994.html
https://www.cnblogs.com/lovevin/p/13122322.html

posted @ 2022-01-07 17:09  失去樱桃的卡Q因  阅读(50)  评论(0)    收藏  举报