zhangjian
2023-06-05 0976d2d0f90cff460cedfdc8bd74e98c2c31a58c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import watchSizeForBrowsersOtherThanIE9 from 'watch-size'
import { removeFromArray } from './removeFromArray'
 
let intervalId
const registered = []
const INTERVAL_DURATION = 100
 
function run() {
  intervalId = setInterval(() => {
    registered.forEach(test)
  }, INTERVAL_DURATION)
}
 
function stop() {
  clearInterval(intervalId)
  intervalId = null
}
 
function test(item) {
  const { $el, listener, lastWidth, lastHeight } = item
  const width = $el.offsetWidth
  const height = $el.offsetHeight
 
  if (lastWidth !== width || lastHeight !== height) {
    item.lastWidth = width
    item.lastHeight = height
 
    listener({ width, height })
  }
}
 
function watchSizeForIE9($el, listener) {
  const item = {
    $el,
    listener,
    lastWidth: null,
    lastHeight: null,
  }
  const unwatch = () => {
    removeFromArray(registered, item)
    if (!registered.length) stop()
  }
 
  registered.push(item)
  // The original watch-size will call the listener on initialization.
  // Keep the same behavior here.
  test(item)
  run()
 
  return unwatch
}
 
export function watchSize($el, listener) {
  // See: https://stackoverflow.com/a/31293352
  const isIE9 = document.documentMode === 9
  // watch-size will call the listener on initialization.
  // Disable this behavior with a lock to achieve a clearer code logic.
  let locked = true
  const wrappedListener = (...args) => locked || listener(...args)
  const implementation = isIE9
    ? watchSizeForIE9
    : watchSizeForBrowsersOtherThanIE9
  const removeSizeWatcher = implementation($el, wrappedListener)
  locked = false // unlock after initialization
 
  return removeSizeWatcher
}