阻止事件传播

上一次学习了DOM 的事件,理解了冒泡事件和捕获事件,触发的机制,今天学习一下具体的应用场景,或者说在哪一个地方容易踩坑。css

作一个小demo,点击按钮出现浮层,点击其它地方关闭浮层,写一个简单csssegmentfault

<style>
.wrapper{
    position:relative;
    display:inline-block;
}
.popover{
    position:absolute;
    border:1px solid red;
    left:100%;
    top:0;
    padding:10px;
    margin-left:10px;
    background:white;
    display: none;  /*默认隐藏*/
}
.popover::before{
    position:absolute;
    content:'';
    top:5px;
    right:100%;
    border:10px solid transparent;
    border-right-color:red;
}
.popover::after{
    position:absolute;
    content:'';
    top:5px;
    right:100%;
    border:10px solid transparent;
    border-right-color:white;
    margin-right:-1px;
}

</style>
<div id="wrapper" class='wrapper'>
    <button id="clickMe">点我</button>
    <div id="popover" class="popover">
        <input type="checkbox">浮层
    </div>
</div>
<script>
    clickMe.addEventListener('click',function(){
        popover.style.display = 'block';
    });
</script>

那如今我要点击页面空白地方关闭呢?该用什么方法,很容易想到监听文档,以下代码浏览器

document.addEventListener('click',function(){
    popover.stely.display = 'none';
});

可是实际上这样写了以后,按钮都失效了,怎么点都没有反应。这是为何呢?
理解上一篇讲的捕获和冒泡事件后就很好理解这点了,能够DOM事件之捕获、冒泡
咱们没有指定监听是在捕获仍是冒泡阶段,浏览器默认是冒泡阶段,当咱们点击按钮时,捕获阶段没有发生何时,可是冒泡阶段就不同了,首先button上函数先触发,而后document上函数也触发了,致使准备出现的浮层又被隐藏了。
那你可能要问,button上的事件执行了没?其实这两个事件都执行了,只是时间过短,浏览器默认一块儿执行了,能够在里面加一个debugger,就能够看到了。app

clickMe.addEventListener('click',function(){
    popover.style.display = 'block';
});

那该怎么解决呢?最简单的方法是,除了要执行popover.style.display = 'block',还要阻止事件传播ide

clickMe.addEventlistener('click',function(){
    popover.style.display = 'block';
});

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

这里为何添加在按钮的父元素上面呢?若是不添加在父元素上面,点击浮层的时候,浮层也会被关闭。函数

若是页面上有不少监听器的话,这个方法是比较浪费内存的,比较省内存的方法用JQuery 作学习

$(clickMe).on('click',function(){
    $(popover).show();
    $(document).one('click',function(){
        $(popover).hide();
    });
});
$(wrapper).on('click',function(e){
    e.stopPropagation();    
})

一开始不监听,只在popover`show`的时候监听一次,立刻关掉,这叫作清理战场。
$(wrapper).on('click',false) 和下面的代码彻底等价flex

$(wrapper).on('click',function(e){
    e.preventDefault();     //阻止默认事件
    e.stopPropagation();    //阻止传播
})

可是若是页面中有checkbox,你在它的父元素任何一层,包括checkbox本身,添加了组织默认事件那么这个checkbox就没办法被checkspa

这里有个问题,若是没有阻止事件传播,向下面这样,会发生什么事情呢?debug

$(clickMe).on('click',function(){
    $(popover).show();
    $(document).one('click',funtion(){
        $(popover).hide();
    });
});

固然了,和以前同样,什么事情也不会发生,那当我点击按钮以后里面都发生了那些事情呢?
当我点击了按钮以后,它会作两件事情,首先把popover`show出来,而后把hide函数添加到document上面,当事件传播到document`,就会又把它给隐藏了。

能够给它添加一个setTimeout()函数来解决这个问题

$(clickMe).on('click',function(){
    $(popover).show();
    setTimeout(function(){
        $(document).one('click',function(){
            $(popover).hide();
        })
    },0)
});

setTimeout(fn,0)这个0不是立刻执行,而是尽快执行,具体是在冒泡结束在执行这里的函数,也就是说,当冒泡结束后,在把监听事件添加到document上面,等待用户下次点击在执行。

用 jQuery 作事件冒泡

<style>
.red.active{
  background:red;
}
.blue.active{
  background:blue;
}
.green.active{
  background:green;
}
.yellow.active{
  background:yellow;
}
.orange.active{
  background:orange;
}
.purple.active{
  background:purple;
}
div{
  border:1px solid black;
  display:flex;
  flex:1;
  padding:20px;
  transition:1s;
  border-radius:100%;
}
*{
  padding:0;
  margin:0;
  box-sizing:border-box;
}
.red{
  height:300px;
  width:300px;
}
</style>
<div class="red">
  <div class="blue">
    <div class="green">
      <div class="yellow">
        <div class="orange">
          <div class="purple"></div>
        </div>
      </div>
    </div>
  </div>
</div>
<script>
var n = 1
$('div').on('click',function(e){
  setTimeout(function(){
    $(e.currentTarget).addClass('active')  
  },n*500)
  n+=1
})
</script>

总结:

  1. 同时监听buttondocument,点啥都没反应,由于两个函数都执行了,用阻止事件传播解决了,比较浪费内存
  2. 好必定的方法是用jQuery 作,点击button后在监听document,关闭了就再也不监听,不阻止事件传播,点啥也没反应,两种解决方法:一种是阻止事件传播,另外一种是添加一个setTimeout()函数。
相关文章
相关标签/搜索