第十一章-js事件

事件绑定和事件冒泡

题目

  • 编写一个通用的事件监听函数
  • 描述事件冒泡的流程
  • 无限下拉图片列表,如何监听每个图片的点击

知识点

  • 事件绑定
  • 事件冒泡
  • 事件代理

事件绑定

通过 addEventListener(type, fn) 进行事件绑定,下面为事件绑定函数简单封装

// 通用的事件绑定函数
function bindEvent(elem, type, fn) {
  elem.addEventListener(type, fn)
}

const a = document.getElementById('link1')
bindEvent(a, 'click', event => {
  console.log(event.target) // 打印的时当前元素 a
  event.preventDefault() // 阻止默认行为
  alert('clicked')
})

事件冒泡

事件冒泡:基于DOM树形结构,事件会顺着触发元素向上冒泡。为父元素绑定事件,当触发子元素时利用事件冒泡机制会触发父元素绑定的事件。应用场景:事件代理

// 通用的事件绑定函数
function bindEvent(elem, type, fn) {
  elem.addEventListener(type, fn)
}

const body = document.body
// 为 body 绑定事件,当点击body的子元素的时候,会冒泡到body身上,因此会触发body上面绑定的事件
bindEvent(body, 'click', event => {
  console.log('body clicked')
  console.log(event.target) // 点击的元素
})

// 当点击p1的时候,p1 会冒泡到body上,通过 stopPropagation() 阻止冒泡
const p1 = document.getElementById('p1')
bindEvent(p1, 'click', event => {
  event.stopPropagation() // 阻止冒泡
  console.log('p1 clicked')
})

事件代理

通过冒泡机制,内部元素不绑定事件,而为外层元素绑定事件,从而实现事件代理。应用场景:无限下拉图片列表,如何监听每个图片的点击

  • 代码简洁
  • 减少浏览器内存的占用
  • 不要滥用代理
a1 a2 a3 a4

通用的事件绑定函数(事件代理和普通绑定)

function bindEvent(elem, type, selector, fn) {
  // 如果是普通绑定,只需要传入三个参数,即把fn设置为selector,selector设置为null
  if (fn == null) {
    fn = selector
    selector = null
  }
  elem.addEventListener(type, event => {
    // 获取触发的元素
    const target = event.target
    // 如果有selector说明是代理的情况,并且触发的元素和传入的元素相同
    if (selector && target.matches(selector)) {
      fn.call(target, event)
    } else {
      // 普通绑定
      fn.call(target, event)   
    }
  })
}

// 普通绑定 注意箭头函数的this指向
const btn1 = document.getElementById('btn')
bindEvent(btn1, 'click', function (event) {
  event.preventDefault() // 阻止默认行为
  alert(this.innerHTML)
})

// 代理绑定
const div1 = document.getElementById('div1')
bindEvent(div1, 'click', 'A', function (event) {
  event.preventDefault()
  alert(this.innerHTML)
})

---------------------------下面为补充内容------------------------------

事件捕获,事件冒泡和事件代理

事件捕获和事件冒泡都是为了解决页面中事件流(事件的执行顺序)的问题。

click me

事件捕获:事件从最外层触发,直到找到最具体的元素。

如上面的代码,在事件捕获下,如果点击p标签,click 事件的顺序应该是 document->html->body->div->p

事件冒泡:事件会从最内层的元素开始发生,一直向上传播,知道触发 document 对象。

因此在事件冒泡下,p 元素发生 click 事件的顺序为 p->div->body->html->document

事件绑定:

js 通过 addEventListener 绑定事件。addEventListener 的第三个参数就是为事件冒泡和事件捕获准备的。

addEventListener 有三个参数:

element.addEventListener(event, function, useCapture)

  • 第一个参数是:需要绑定的事件
  • 第二个参数是:触发事件后要执行的函数
  • 第三个参数是:默认值是 false ,表示在 事件冒泡阶段 调用事件处理函数;如果设置为 true ,则表示在 事件捕获阶段 调用事件处理函数。

事件代理(事件委托)

对于事件代理来说,在事件捕获或者事件冒泡阶段处理并没有明显的优劣之分,但是由于事件冒泡的事件流模型被所有的主流浏览器兼容,从兼容性角度来说通常使用事件冒泡模型。

为什么要使用事件代理?
比如100个(甚至更多)li 标签绑定事件,如果一个一个绑定,不仅相当麻烦,还会占用大量的内存空间,降低性能。而使用事件代理作用如下:

  • 代码简洁
  • 减少浏览器内存占用

事件代理的原理:

事件代理(事件委托)是利用事件的冒泡原理来实现的,比如当我们点击内容的li标签时,会冒泡到外层的ul标签上。因此,当我们想给很多个li标签添加事件的时候,可以给他的父级元素添加对应的事件,当触发任意li元素时,会冒泡到其父级元素,这时绑定在父级元素的事件就会被触发,这就是事件代理(委托),委托他们的父级元素代为执行事件。

demo

  • 111
  • 222
  • 333
  • 444

参考文章:https://segmentfault.com/a/1190000005654451

你可能感兴趣的:(第十一章-js事件)