1. 90前端首页
  2. 前端框架

Vue造轮子-popover组件(中)

1. 现在遇到的问题

  • 如果在popover外面包了个div写上overflow:hidden就会出bug,所以要把弹出的div放到按钮的同一个层级
  • 关于click事件的,之前解决的方式是写click.stop,但是其实还是会有bug,会打断用户的事件链,用户在外面写@click,点击按钮没有用,但是点击按钮周围空白区域会有,那么就会导致别人用了组件无法自己添加click事件,所以不能用stop解决这个问题。

2. 解决overflow:hidden的问题

 methods: {
    xxx(){
      this.visible = !this.visible
      if(this.visible === true) {
        setTimeout(()=>{
        // 主要是下面这四句实现,但是还是有bug
        document.body.appendChild(this.$refs.contentWrapper)
        let {width, height, top, left} = this.$refs.triggerWrapper.getBoundingClientRect()
        this.$refs.contentWrapper.style.left = left + \'px\'
        this.$refs.contentWrapper.style.top = top + \'px\'
        // 
          let eventHandler = ()=>{
            this.visible = false;
            console.log(\'document 隐藏 popover\')
            document.removeEventListener(\'click\',eventHandler)
          }
          document.addEventListener(\'click\', eventHandler)
        })
      }else{
        console.log(\'vm 隐藏 popover\')
      }
    }

3. 面试题:v-show和v-if的区别,v-if是是否出现在dom树上,v-show是改变其css样式。

4. 解决当容器有 overflow hidden 造成的bug

  • clientRect是相距可视范围,绝对定位相距于body定位。现在我们的浮层是相对于body定位,而按钮获取到的top是相对于window定位而引发的bug。
  • 解决这个问题只要得到两者之间的插值就好解决
     methods: {
        xxx(){
          this.visible = !this.visible
          if(this.visible === true) {
            setTimeout(()=>{
              document.body.appendChild(this[\'$refs\'][\'contentWrapper\'])
              let {top, left} =this[\'$refs\'][\'triggerWrapper\'].getBoundingClientRect()
              // 这两句话解决
              this[\'$refs\'][\'contentWrapper\'].style.left = left + window.scrollX + \'px\' 
              this[\'$refs\'][\'contentWrapper\'].style.top = top + window.scrollY +\'px\'
              // 
              let eventHandler = ()=>{
                this.visible = false;
                console.log(\'document 隐藏 popover\')
                document.removeEventListener(\'click\',eventHandler)
              }
              document.addEventListener(\'click\', eventHandler)
            })
          }else{
            console.log(\'vm 隐藏 popover\')
          }
        }

5. 解决外部点击click无效的问题。

    // 先将点按钮和点外面的逻辑分开
    onClick(event){
      if(this.$refs.triggerWrapper.contains(event.target)){
        console.log(\'按钮\')
        this.visible = !this.visible
        
      } else {
        console.log(\'其它\')
      }
    }

    // 将之前的代码移动进去
     methods: {
      onClick(event){
        if(this.$refs.triggerWrapper.contains(event.target)){
          this.visible = !this.visible
          if(this.visible === true) {
            setTimeout(() => {
              document.body.appendChild(this[\'$refs\'][\'contentWrapper\'])
              let {top, left} = this[\'$refs\'][\'triggerWrapper\'].getBoundingClientRect()
              this[\'$refs\'][\'contentWrapper\'].style.left = left + window.scrollX + \'px\'
              this[\'$refs\'][\'contentWrapper\'].style.top = top + window.scrollY + \'px\'
              let eventHandler = (e) => {
                if(this[\'$refs\'][\'contentWrapper\'].contains(e.target)){ 
                  // 这句话解决了点击内容消失的问题
                } else {
                  this.visible = false;
                  document.removeEventListener(\'click\', eventHandler)
                  console.log(\'关闭\') // document事件引起的
                }
              }
              document.addEventListener(\'click\', eventHandler)
            })
          }
        } else {
          console.log(\'非按钮\')
        }
      }
    }

6.开始重构上面那段代码

    methods: {
    positionContent() {
      document.body.appendChild(this[\"$refs\"][\"contentWrapper\"])
      let {top, left} = this[\"$refs\"][\"triggerWrapper\"].getBoundingClientRect()
      this[\"$refs\"][\"contentWrapper\"].style.left = left + window.scrollX + \"px\"
      this[\"$refs\"][\"contentWrapper\"].style.top = top + window.scrollY + \"px\"
    },
    listenToDocument() {
      let eventHandler = (e) => {
        if (this[\"$refs\"][\"contentWrapper\"].contains(e.target)) { // 这句话解决了点击内容消失的问题
        } else {
          this.visible = false
          console.log(\'关闭\')
          document.removeEventListener(\"click\", eventHandler)
          console.log(\"关闭\") // document事件引起的
        }
      }
      document.addEventListener(\"click\", eventHandler)
    },
    listenToDocument(){
      let eventHandler = (e) => {
        if ( this[\"$refs\"][\"contentWrapper\"] &&
          this[\"$refs\"][\"contentWrapper\"].contains(e.target)) { // 这句话解决了点击内容消失的问题
          return
        } else {
          this.visible = false
          document.removeEventListener(\"click\", eventHandler)
          console.log(\"关闭\") // document事件引起的
        }
      }
      document.addEventListener(\"click\", eventHandler)
    },
    opShow(){
      setTimeout(() => {
        this.positionContent()
        this.listenToDocument()
      })
    },
    onClick(event) {
      if (this[\"$refs\"][\"triggerWrapper\"].contains(event.target)) {
        this.visible = !this.visible
        if (this.visible === true) {
          this.opShow()
        } else {
          console.log(\'关闭\')
        }
      }
    }
  },

7. 还有一个bug,上面打印关闭,关闭了两次

  • 原因是document会去关闭它,onClick也会去关闭它
  • 我们需要把关闭入口收拢,这个就是代码的紧密性,也就是高内聚低耦合的内聚。
        methods: {
        onClickDocument(e){
          if ( this[\"$refs\"][\"popover\"] && (this[\"$refs\"][\"popover\"] &&
            this[\"$refs\"][\"popover\"].contains(e.target))) {return}
          else {
            this.close()
          }
        },
        positionContent() {
          document.body.appendChild(this[\"$refs\"][\"contentWrapper\"])
          let {top, left} = this[\"$refs\"][\"triggerWrapper\"].getBoundingClientRect()
          this[\"$refs\"][\"contentWrapper\"].style.left = left + window.scrollX + \"px\"
          this[\"$refs\"][\"contentWrapper\"].style.top = top + window.scrollY + \"px\"
        },
    
        open(){ // 打开的收拢
          this.visible = true
          setTimeout(() => {
            this.positionContent()
            document.addEventListener(\"click\", this.onClickDocument)
          })
        },
        close(){ // 关闭的收拢
          this.visible = false
          document.removeEventListener(\"click\", this.onClickDocument)
        },
        onClick(event) {
          if (this[\"$refs\"][\"triggerWrapper\"].contains(event.target)) {
            if (this.visible === true) {
              this.close()
            } else {
              this.open()
            }
          }
        }
      },
      // 所有重要的操作都要进行收拢

本文来自网络整理,转载请注明原出处:https://segmentfault.com/a/1190000021660476

展开阅读全文

发表评论

登录后才能评论