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()
          }
        }
      }
    },
    // 所有重要的操作都要進行收攏

最後,個人微信,歡迎交流!

wechat.jpg

發佈了25 篇原創文章 · 獲贊 0 · 訪問量 1220
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章