class/DomResize.js

import { Event } from './Event'

/**
 * @description 节点大小监测。
 * @example
 * // 使用
 * let event = new DomResize(document.querySelector('#contianer'))
 * event.on('dom-resize', callback)
 */

export class DomResize extends Event {
  width = 20000
  oldWidth = 0
  newWidth = 0
  oldHeight = 0
  newHeight = 0
  supportsPassive = false
  constructor (el) {
      super()
      this.el = el
      this._init()
  }
  _init () {
      this.oldWidth = parseFloat(window.getComputedStyle(this.el).width)
      this.oldHeight = parseFloat(window.getComputedStyle(this.el).height)
      this.setSupportsPassive()
      this.createNode()
  }

  createNode () {
      // 监听变大的DOM
      const holderBig = document.createElement('div')

      holderBig.style =
      'position: absolute;top:0;left: 0;bottom: 0;right: 0;overflow: hidden;visibility: hidden;z-index:-1'
      holderBig.innerHTML = `<div style="width:${this.width}px;height:${this.width}px"></div>`

      // 监听变小的DOM
      const holderSmall = document.createElement('div')

      holderSmall.style =
      'position: absolute;top:0;left: 0;bottom: 0;right: 0;overflow: hidden;visibility: hidden;z-index:-1'
      holderSmall.innerHTML = '<div style="width:300%;height:300%"></div>'

      this.holderBig = holderBig
      this.holderSmall = holderSmall
      this.el.appendChild(holderBig)
      this.el.appendChild(holderSmall)

      holderSmall.scrollTop = this.width
      holderSmall.scrollLeft = this.width
      holderBig.scrollTop = this.width
      holderBig.scrollLeft = this.width

      holderBig.addEventListener(
          'scroll',
          this.scroll,
          this.supportsPassive
              ? {
                  passive: true
              }
              : false,
          false
      )
      holderSmall.addEventListener(
          'scroll',
          this.scroll,
          this.supportsPassive
              ? {
                  passive: true
              }
              : false,
          false
      )
  }

  scroll = () => {
      this.newWidth = parseFloat(window.getComputedStyle(this.el).width)
      this.newHeight = parseFloat(window.getComputedStyle(this.el).height)
      // 只有两次width不同时才分发事件,不然会多次分发
      if (this.oldWidth !== this.newWidth || this.oldHeight !== this.newHeight) {
          this.emit('dom-resize')
          this.oldWidth = this.newWidth
          this.oldHeight = this.newHeight
      }
      // 每次触发滚动事件后,重新将滚动条设至尽头
      this.holderSmall.scrollTop = this.holderBig.scrollTop = this.width
      this.holderSmall.scrollLeft = this.holderBig.scrollLeft = this.width
  }

  setSupportsPassive () {
      try {
          const opts = Object.defineProperty({}, 'passive', {
              get: () => {
                  this.supportsPassive = true
                  return true
              }
          })

          window.addEventListener('testPassive', null, opts)
          window.removeEventListener('testPassive', null, opts)
      } catch (e) {
          console.error(e)
      }
  }

  destroy () {
      this.holderBig.removeEventListener('scroll', this.scroll)
      this.holderSmall.removeEventListener('scroll', this.scroll)
      this.el.removeChild(this.holderBig)
      this.el.removeChild(this.holderSmall)
  }
}