美文网首页
触发 / 关闭浮层

触发 / 关闭浮层

作者: 养乐多__ | 来源:发表于2019-05-15 15:07 被阅读0次

    实现功能:点击按钮触发浮层,点击别处关闭浮层。

    • html 代码:
    <div id="wrapper" class="wrapper">
      <button id="clickMe">点击</button>
      <div id="popover" class="popover">
        <input type="checkbox">浮层
      </div>
    </div>
    
    • 部分 css 代码:
    .popover{
      display: none;
    }
    

    1. 方案一 --- 用 DOM Events 实现

    1. 如上,浮层的样式默认为“不显示 ”。我们监听 button 点击事件,使 button 被点击时显示浮层。
    clickMe.addEventListener('click', function(){
      popover.style.display = 'block'
    })
    
    1. 实现点别处关闭浮层时,可以监听 document
      注意:不要监听 body,因为 body 是被文档流撑起来的,高度很小,空白处可能取不到 body
    document.addEventListener('click', function(){
      popover.style.display = 'none'
    })
    
    1. 因为点击 buttonpopoverdocument 也会被点击,导致无法触发浮层。所以要在它们的父元素 wrapper阻断冒泡
    wrapper.addEventListener('click', function(e){
      e.stopPropagation() //停止传播,阻断冒泡
    })
    

    2. 方案二 --- 用 jQuery 实现

    1. 同理,我们改为 jQuery 语句:
    $(clickMe).on('click', function(){
      $(popover).show()
    })
    $(wrapper).on('click', function(e){
      e.stopPropagation()
    })
    $(document).on('click', function(){
      $(popover).hide()
    })
    
    1. 同时阻止传播和阻止默认事件
      jQuery 提供了一个方便的写法,用 false 可以同时阻止传播和阻止默认事件。但此处不可以用,因为会导致无法勾选 checkbox(默认它的动作被阻止)而出现 bug。
    $(wrapper).on('click', false)  //同时阻止传播和阻止默认事件
    // 等价于
    $(wrapper).on('click', function(e){
      e.preventDefalt()
      e.stopPropagation()
    })
    

    所以我么平时使用 preventDefault 时一般不要直接放在 div 上。

    1. 节省内存
      document 处于一直被监听的状态,非常浪费内存。为了节省内存,我们可以使它只在浮层出现的时候被监听一次。
    $(clickMe).on('click', function(){
      $(popover).show()
      $(document).one('click', function(){ // 只在 button 被点击时监听 document 
        $(popover).hide()
      })
    })
    $(wrapper).on('click', function(e){
      e.stopPropagation()
    })
    
    3. 完善功能

    为使浮层更具实用性,我们使其最终实现的功能包括:

    • 点击按钮弹出浮层
    • 点击别处关闭浮层
    • 点击浮层时,浮层不得关闭
    • 再次点击按钮,浮层消失

    为了更好地学习理解 DOM Events,选择用方案一来实现:

    clickMe.addEventListener('click',function(e){
        if(popover.style.display === 'none'){ // 若浮层在关闭状态
            popover.style.display = 'block' // 显示浮层
            e.stopPropagation()  // 阻止冒泡
        }else{
            popover.style.display = 'none' // 否则关闭浮层
        }
    })
    document.addEventListener('click',function(){
            popover.style.display = 'none'
        })
    popover.addEventListener('click',function(e){
        e.stopPropagation() 
    })
    

    但是在调试时发现存在 bug:运行代码后首次点击 button 并不会触发浮层。
    后来发现,因为我直接在 js 中用 style 去控制样式,而它是直接去获取元素上的 style 属性的,因此之前写在 css 里的 display 属性它获取不到(除非用 window.getComputedStyle 去获取),首次点击按钮时 display 相当于是空字符串。

    4. 优化代码
    • 由上可知,除非不得已,我们最好不要在 js 中直接用 style 来控制样式(容易出现 bug 且不好 debugger),而是改用切换 class 状态的方法。
    • 改进方法:在 css 中添加一个类,只需判断浮层 popover 当前是否包含这个类,然后进行添加和移除操作。

    首先在 css 中添加一个类 show 来显示浮层:

    .show{
      display: block;
    }
    

    完整的 js 代码:

    clickMe.addEventListener('click', function(e) {
      let p1 = document.getElementById('popover')
      if (!p1.classList.contains('show')) { // 判断当前类是否包含 show 
        p1.classList.add('show')
        e.stopPropagation() // 停止传播,阻断冒泡
      } else {
        p1.classList.remove('show')
      }
      document.addEventListener('click', function() {
        p1.classList.remove('show')
      })
    })
    popover.addEventListener('click', function(e) {
      e.stopPropagation()
    })
    

    相关文章

      网友评论

          本文标题:触发 / 关闭浮层

          本文链接:https://www.haomeiwen.com/subject/gvbpaqtx.html