Web 前端开发 让前端飞程序员

理解Event的冒泡模型

2018-01-16  本文已影响113人  吴少在coding

本文探索一下Event的冒泡过程和初学遇到的几个小bug

DOM Event概述

Event接口是检测在DOM中的发生的所有事件,我们一直在用,而且从DOM的很早的版本就一直在用着。早期的网景(后来的火狐)和IE是各自为战,直到W3C一统江湖,DOM版本一路发展而来,经历了DOM-0(洪荒时代)、DOM-1(只有两章核心内容)、DOM-2(划时代的一个版本,我们学的Event就在这个版本,而且目前的用的也是这个版本)、DOM-3、DOM-4(草案阶段)。

//1、有一个js函数如下
function print(){
  console.log(1)
}

//2、在html的button里面点击触发上面的函数
<button id=button onclick="?">点我</button>
//问号处填可以填什么 A. print() B.print C.print.call()

//在js里面的onclick里面触发
button.onclick = ?
//问号处可以填什么 A. print() B.print C.print.call()

既然onclick等on事件在JS中是一个属性,那么后面的就会覆盖前面的,所以DOM2里面引入了一个重要的EventListener,是一个队列。

addEventListener

这是一个队列,例子1,先进先出的特点,为后面的冒泡模型做准备。

function f(){
  console.log("eventListener不会覆盖")
}

button2.addEventListener('click', function(){
  console.log("eventListener不会覆盖1")
})
button2.addEventListener('click', f)
button2.removeEventListener('click', f)
button2.addEventListener('click', function(){
  console.log("eventListener不会覆盖3")
})
function f(){
  console.log("eventListener不会覆盖2")
  button2.removeEventListener('click', f)
}


button2.addEventListener('click', f)

只会打印一次,不会一直打印了,也就是one的原理。

W3C的模型

冒泡模型

上面的官方文档中,我只研究一下捕获阶段(capture phase)和冒泡阶段(bubbling phase)。

grand.addEventListener('click', function(){
  console.log('我是你爷爷')
})
dad.addEventListener('click', function(){
  console.log('我是你爸爸')
})

son.addEventListener('click', function(){
  console.log('我是你儿子')
})
冒泡排序
grand.addEventListener('click', function(){
  console.log('我是你爷爷')
}, true)
dad.addEventListener('click', function(){
  console.log('我是你爸爸')
}, true)

son.addEventListener('click', function(){
  console.log('我是你儿子')
}, true)
简单的图解

上图是简单的图解,注意优先运行为true的部分,再运行false的部分。

简单的实例====================>demo

grand.addEventListener('click', function(){
  console.log('我是你爷爷')
}, true)
dad.addEventListener('click', function(){
  console.log('我是你爸爸')
})

son.addEventListener('click', function(){
  console.log('我是你儿子')
变式

一个奇葩的问题

son.addEventListener('click', function(){
  console.log('我是你儿子true')
}, true)

son.addEventListener('click', function(){
  console.log('我是你儿子false')
})
奇葩

意想不到的Bug

parent是关键字不能使用,一不小心使用的话会出问题。

意外bug

点击空白,对话框消失的案例

第一个bug

正常来说,应该点击body控制台打印数字1,你点烂了你的罗技鼠标也没出来。为什么呢?

body的位置

使用了红色border之后,发现body的高度太矮了,点击不到啊。

第二个bug

根据图片 中的控制台可以发现,确实都点击到了,监听没问题,而且点击后,也是按照冒泡的顺序打印的结果。

正常的现象

注释掉出问题的代码后,上图是正常的点击出现对话框啊,说明问题就出在注释的代码上。

阻止冒泡

修复第二个bug

我们既然知道了第二个bug产生的原因,那么我们阻止冒泡顺序

clickMe.addEventListener('click', function(){
  popover.style.display = 'block'
  console.log('点击浮层了') 
})

wrapper.addEventListener('click', function(e){
  e.stopPropagation()
})


document.addEventListener('click', function(){
  popover.style.display = 'none'
  console.log('点击文档了') 
})
$(clickMe).on('click', function(){
  $(popover).show()
  console.log('show')
  setTimeout(function(){
    console.log('one click')
    $(document).one('click', function(){
     console.log('我觉的他不会执行')
     $(popover).hide()            
    })
  },0)
  
})
// $(wrapper).on('click', function(e){
//   e.stopPropagation()
// })

$(document).on('click', function(){
  console.log('走到document啦')
})

jQuery节省内存 具体的分析

JS版本的节省内存的版本==================>节省内存

jQuery版本的节省内存版本=================>jQuery节省内存

对话框小三角的制作

.popover{
  display: inline-block;
  border: 1px solid red;
  position: relative;
  padding: 10px;
  margin:10px;
}
.popover::before{
  position: absolute;
  content: '';
  top: 5px;
  right: 100%;
  border: 10px solid transparent;
  border-right-color:red;
}
.popover::after{
  content: '';
  border: 10px solid transparent;
  position: absolute;
  right: 100%;
  top: 5px;
  border-right-color: white;
  margin-right: -1px;
}

主要利用boder-right-color以及两个伪元素。

浮层三角的实例=============================>demo

冒泡的直观体现

点击一下会有惊喜的https://github.com/codevvvv9/bubble/blob/master/bubble.gif

冒个泡

上一篇 下一篇

猜你喜欢

热点阅读