dom-size-monitor
Version:
监听元素大小变化
90 lines (80 loc) • 2 kB
JavaScript
import debounce from '../debounce'
import { SensorStyle, SensorClassName } from '../constant'
export const createSensor = element => {
// 感应器
let sensor = null
// callback
let listeners = []
const newSensor = () => {
// 调整样式
if (getComputedStyle(element).position === 'static') {
element.style.position = 'relative'
}
const obj = document.createElement('object')
obj.onload = () => {
obj.contentDocument.defaultView.addEventListener('resize', resizeListener)
// 直接触发一次 resize
resizeListener()
}
obj.setAttribute('style', SensorStyle)
obj.setAttribute('class', SensorClassName)
obj.type = 'text/html'
// 添加到 dom 结构中
element.appendChild(obj)
// 对于 ie 需要滞后,否则白屏,所以放到后面
obj.data = 'about:blank'
return obj
}
/**
* 统一触发 listeners
*/
const resizeListener = debounce(() => {
// 依次触发执行
listeners.forEach(listener => {
listener(element)
})
})
const bind = cb => {
// 如果不存在 sensor,则创建一个 object
if (!sensor) {
sensor = newSensor()
}
if (listeners.indexOf(cb) === -1) {
listeners.push(cb)
}
}
const destroy = () => {
if (sensor && sensor.parentNode) {
if (sensor.contentDocument) {
// 移除事件
sensor.contentDocument.defaultView.removeEventListener('resize', resizeListener)
}
// 移除 dom
sensor.parentNode.removeChild(sensor)
// 初始化
sensor = undefined
listeners = []
}
}
/**
* 取消绑定
* @param cb
*/
const unbind = cb => {
const idx = listeners.indexOf(cb)
if (idx !== -1) {
listeners.splice(idx, 1)
}
// 不存在 listener,并且存在 sensor object
// 则移除 object
if (listeners.length === 0 && sensor) {
destroy()
}
}
return {
element,
bind,
destroy,
unbind
}
}