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。
  • 解決這個問題只要獲得二者之間的插值就好解決css

    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

相關文章
相關標籤/搜索