DOM事件模型

DOM leave 0:

  • xxx.onclick = function(){ ... }
DOM事件模型_第1张图片
onclick

onclick="xxx()" == eval(xxx())

DOM事件模型_第2张图片
eval

onclick是属性,具有唯一性

DOM leave 2:
xxx.onclick = function() {}只能给元素绑定一个onclick事件
xxx.addEventListener('click', function(){ ... }) 可以绑定多个事件,可看作队列(先进先出)。
xxx.removeEventListener('click', function() {}) 取消click队列。

删除事件队列:

function f1(){
  console.log(1)
}
function f2(){
  console.log(2)
}
function f3(){
  console.log(3)
}
xxx.addEventListener('click', f1)

xxx.addEventListener('click', f2)

xxx.removeEventListener('click', f1)

xxx.addEventListener('click', f3)

xxx.removeEventListener('click', f3)

只有一次事件监听的按钮:

function f1(){
  console.log(1)
  xxx.removeEventListener('click', f1)
}
xxx.addEventListener('click', f1)

事件捕获与冒泡
html:

爷爷
父亲
儿子

js:

//1 当我点击儿子的时候,是否点击了父亲和爷爷?
// yes1

//2 当我点击儿子的时候,三个函数是否调用
grand1.addEventListener('click', function fn1(){
  console.log('爷爷')
})
parent1.addEventListener('click', function fn2(){
  console.log('父亲')
})
child1.addEventListener('click', function fn3(){
  console.log('儿子')
})
// yes2 

//3 请问fn1 fn2 fn3 的执行顺序
// 123  or  321
// 321

//不传第三个参数/传  儿子爸爸爷爷
//第三个参数传true   爷爷爸爸儿子
DOM事件模型_第3张图片
DMO事件模型

先从上往下(捕获阶段),再从下往上(冒泡阶段)。
如果第三个参数传的是false(或者不传,默认false),走右边(冒泡)。儿子爸爸爷爷。
如果第三个参数传的是true,走左边(捕获)。爷爷爸爸儿子。

child1.addEventListener('click', function fn3(){
  console.log('儿子2')
},true)
child1.addEventListener('click', function fn3(){
  console.log('儿子1')
})

如果是在本身触发,不区分捕获冒泡,按照代码顺序执行。

DOM事件模型续...
如何做到点击按钮显示浮层,点击别处隐藏浮层?
:




  
  JS Bin


浮层

:

body{
  border: 1px solid red;
}
.wrapper{
  position: relative;
  display: inline-block;
}
.popover{
  background: white;
  border: 1px solid red;
  position: absolute;
  left: 100%;
  top: 0;
  white-space: nowrap;
  padding: 10px;
  margin-left: 10px;
  display: none;
}
.popover::before{
  position: absolute;
  right: 100%;
  top: 5px;
  border: 10px solid transparent;
  border-right-color: red;
  content: '';
}
.popover::after{
  position: absolute;
  right: 100%;
  top: 5px;
  border: 10px solid transparent;
  border-right-color: white;
  content: '';
  margin-right: -1px;
}
这是一个很丑很丑的浮层

:

clickMe.addEventListener('click', function fn1(){
  popover.style.display = 'block'
  console.log('block')
})
document.addEventListener('click', function fn2(){
  popover.style.display = 'none'
  console.log('none')
})

ok,首先这个方法是行不通的,因为当我们点击button时,我们也相当于点击document,在冒泡阶段会执行到fn2,并且我们知道在冒泡阶段函数的执行过程是fn1-fn2,所以最后点击按钮是不会显示浮层的。
接下来我们让button阻止冒泡:

clickMe.addEventListener('click', function fn1(e){
  popover.style.display = 'block'
  console.log('block')
 e.stopPropagation()  //阻止冒泡向上传播
})

这段代码会在button处中断冒泡过程,导致document不能执行函数fn2,所以这样做可以达到我们所要的效果,但是这里有一个bug,如果我们给浮层加上一个checkbox:

浮层
有checkbox的浮层

这个时候我们点击checkbox,会隐藏浮层,为什么?
因为button和浮层都是在wrapper中,为兄弟关系,botton并不会被点击,但浮层依然在document中,事件会通知到document,导致浮层隐藏,那么怎么解决呢?
很简单,我们在浮层和button的父元素wrapper上添加事件并删除button的阻止冒泡代码:

clickMe.addEventListener('click', function fn1(e){
  popover.style.display = 'block'
  console.log('block')
})

wrapper.addEventListener('click', function(e){
   e.stopPropagation()  //阻止冒泡向上传播
})

因为冒泡阶段是从小到大,会经过父元素wrapper,我们只需要在wrapper上中断冒泡过程就ok了。
此时再点击checkbox就不会导致浮层隐藏。
但是这种方法会浪费内存,因为document和popover相对监听,如果有很多很多popover,那么document上就要做对应个数的监听,非常浪费内存,所以这个版本不太实用。
更新版:

$(clickMe).on('click',function () {
    $(popover).show();
});
$(wrapper).on('click',false);  

$(document).on('click',function () {
    $(popover).hide();
});

请注意,这是个错误的示范,false会阻止所有默认事件以及冒泡,导致checkbox无法点击,并且依然没有改善内存问题。
再次更新:

$(clickMe).on('click',function(){
  console.log('被点击了')
  $(popover).show()
    //每次点击button,document只监听一次click事件,关闭浮层后不再监听,这样就做到了节省内存
    $(document).one('click',function(){
      $(popover).hide()
    })
})

$(wrapper).on('click', function(e){
   e.stopPropagation()  //阻止冒泡向上传播
})

再次更新版:点击按钮显示浮层和关闭浮层。

$(clickMe).on('click',function(){
   if($(popover).css('display') === 'none'){
     $(popover).show()
  }else{
     $(popover).hide()
  }
    $(document).one('click',function(){
      $(popover).hide()
    })

})
$(wrapper).on('click', function(e){
   e.stopPropagation()  //阻止冒泡
})

面试题:如果没有阻止冒泡,点击button不会出现浮层,为什么呢?
答:在冒泡阶段,执行clickMe的函数,执行完$(popover).show()之后就为document添加监听事件,导致document拥有函数,这个过程是在冒泡结束之前进行的,所以当clickMe的函数执行完之后,继续执行document的监听时间函数。

你可能感兴趣的:(DOM事件模型)