Skip to content

Latest commit

 

History

History
86 lines (75 loc) · 5.15 KB

DOM事件模型.md

File metadata and controls

86 lines (75 loc) · 5.15 KB

标准的发布

2002年,W3C发布了新的事件触发机制
不过在这之前Netscape (网景)和 IE在这件事情互不相让。
网景认为,事件发生后是由外向内传播的。而IE跟网景是相反的,主张事件发生后是由内向外传播。
两家主张的事件标准如下(这里以为点击事件为例)

Node.attachEvent('onclick', fn)		//IE的标准,也就是后来的冒泡
Node.addEventListener('click', fn)	//网景的标准,也就是后来的捕获

那个时候的开发者也是非常头疼的,在ie下面要用ie的标准,在网景的浏览器则要用网景的标准。
于是W3C让两家和谈,最后在2002年发布了新标准。

事件传播

W3C把网景和IE两家的标准整合成一起,规定浏览器应该同时支持两种调用顺序,它分为三个阶段。

  • 第一阶段:从window对象传导到目标节点(上层传到底层),称为“捕获阶段”。
  • 第二阶段:在目标节点上触发,称为“目标阶段”。
  • 第三阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”。

image.png
如上图,最底层的td标签被点击了,就会先问Window有没有函数要执行,如没有就会一直问下去直到td标签。
这个过程走完之后,就来到了目标阶段,可以选择是否冒泡。如选择冒泡则从td标签一直冒到Window上。

事件监听

W3C发布的新标准,规定了统一使用EventTarget.addEventListener()给当前节点绑定一个特定事件的监听函数,一旦这个事件发生,就会执行监听函数。

语法

target.addEventListener(type, listener[, useCapture]);

参数

  • type:事件名称,大小写敏感。
  • listener:监听函数。事件发生时,会调用该监听函数。
  • useCapture:布尔值,如果设为true,表示监听函数将在捕获阶段(capture)触发。该参数可选,如不写则默认值为false,监听函数会在冒泡阶段被触发。
function fn(){
  console.log('hello')
}
        
div.addEventListener('click', fn)

上面的代码给divaddEventListener方法绑定了一个click事件的监听函数fn()。该函数在冒泡阶段触发。

优点
EventTarget.addEventListener是推荐的指定监听函数的方法。
它有如下优点:

  • 同一个事件可以添加多个监听函数。
  • 能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数。

取消冒泡

捕获阶段是不可以取消的,只有冒泡阶段才能取消,stopPropagation方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上的事件监听函数

function fn(e){
	e.stopProgation()
}

div.addEventListener('click', fn)

上面代码,click事件将不会冒泡到div节点的父节点。

事件委托

我们知道了监听函数的定义,但是如果遇到了一次性要给几十个,甚至几百个元素定义监听事件呢?
别慌,我们可以把监听事件定义到它们的父元素,由父元素的监听函数统一处理多个子元素的事件。
这种方法叫做事件委托

let ul = document.querySelector('ul')

ul.addEventListener('click', (e)=>{
	let t = e.target
  if(t.tagName.toLowerCase() === 'li'){
    console.log(t.textContent + '被点击了')
  }
})

上面代码中,click事件的监听函数定义在<ul>节点,但是实际上,它处理的是子节点<li>click事件。

优点
像上面事件委托的例子,只要定义一个监听函数,就能处理多个子节点的事件,而不用在每个

  • 节点上定义监听函数。这样做的好处是能节省监听函数的数量,内存也不会太多。
    它还有一个好处,就是能监听目前不存在而以后会被添加的子节点,这个叫监听动态元素。

    setTimeout(()=>{
      let button = document.createElement('button')
      button.textContent = 'click 1'
      div.appendChild(button)
    },1000)
    
    div.addEventListener('click',(e)=>{
      let t = e.target
      if(t.tagName.toLowerCase() === 'button'){
        console.log(t.textContent + '被点击了')
      }
    })

    上面代码中,我们直接监听父元素div的点击事件,这样它一添加子元素监听函数依然有效。

    以上就是本次DOM事件模型的全部内容了,感谢观看。
    本文参考:阮一峰. 网道:事件