js怎么监听div元素的resize

  在实现一个项目需求的时候,需要监听到某个div元素的宽高变化,第一时间想到的是resize事件,但是很不幸运的是,resize事件只能加在window对象上,并不能监听具体某个DOM元素。

  多方查阅之后,了解到MutationObserver,这是一个可以用来监听整个DOM中任何变化的东西,可以把它理解为一个类,实例化之后调用类实例的几个简单接口即可完成监听,以下具体介绍。

一、MutationObserver介绍

  1.构造函数为window.MutationObserver,参数为一个回调函数。

  监控到DOM中的改变并且等待一系列改变结束后就会触发回调函数。它与事件的不同之处在于,它在DOM变化时,会记录每一个DOM的变化(为一个MutationRecord对象),但是到DOM变化结束时触发回调。DOM变化可能是一系列的(比如元素的宽和高同时改变),那么这一系列的变化就会产生一个队列,这个队列会作为参数传递给回调函数。

  由于浏览器差异的原因,一些版本的浏览器各自支持了构造函数,但是用法都是一样的,实例化一个观察者的代码如下:

let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
let observer = new MutationObserver(callback)    

  2.调用接口开始监控DOM。

  常用的接口有三个:

  ①observe(element, options) 配置MutationObserver在DOM更改匹配给定选项时,通过其回调函数开始接收通知。

   element即要监听的DOM元素,options为监听选项对象,可选的选项如下:

MutationObserver监听选项
选项取值描述
childListtrue/false设置为true表示监听指定元素的子元素的变动
attributestrue/false设置为true表示监听指定元素的属性的变动
characterDatatrue/false设置为true表示监听指定元素的data变动
subtreetrue/false设置为true表示不仅监听目标元素也同时监听其子元素变动,不能单独设置此选项,必须至少包含前三个选项中的一个
attributeOldValuetrue/falseattributes属性已经设为true的前提下,设置为true则会记录节点旧的属性值到MutationRecord的recordOldValue属性。
characterDataOldValuetrue/falsecharacterData属性已经设为true的前提下,设置为true则会记录节点旧的数据到MutationRecord的recordOldValue属性。
attributeFilter监听的属性数组,比如['style',...]配置监听数组内的属性变化,数组外的属性变化会被忽略

   所以监听元素宽高变化,就是监听其style属性变化:

observer.observe(element, { attributes: true, attributeFilter: ['style'], attributeOldValue: true })

   这样当元素的style发生改变的时候,就会触发构造函数中传入的callback函数。

  ②disconnect()  阻止 MutationObserver 实例继续接收的通知,直到再次调用其observe方法,该观察者对象包含的回调函数都不会再被调用。

  ③takeRecords() 从MutationObserver的通知队列中删除所有待处理的通知,并将它们返回到一个MutationRecord对象构成的新数组中。

二、示例

  这里以Vue中的一个组件作为实例,了解了以上所述内容后其实非常简单,代码如下:

<template>
  <div class="container">
    <div class="resize-element">
      改变大小试试
    </div>
    <div class="resize-record">
      触发了{{firedNum}}次resize事件。
    </div>
  </div>
</template>

<script>
export default {
  showName: '监听DOM变化',
  data () {
    return {
      observer: null,
      firedNum: 0,
      recordOldValue: { // 记录下旧的宽高数据,避免重复触发回调函数
        width: '0',
        height: '0'
      }
    }
  },
  mounted () {
    let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
    let element = document.querySelector('.resize-element')
    this.observer = new MutationObserver((mutationList) => {
      for (let mutation of mutationList) {
        console.log(mutation)
      }
      let width = getComputedStyle(element).getPropertyValue('width')
      let height = getComputedStyle(element).getPropertyValue('height')
      if (width === this.recordOldValue.width && height === this.recordOldValue.height) return
      this.recordOldValue = {
        width,
        height
      }
      this.firedNum += 1
    })
    this.observer.observe(element, { attributes: true, attributeFilter: ['style'], attributeOldValue: true })
  },
  beforeDestroyed () {
    if (this.observer) {
      this.observer.disconnect()
      this.observer.takeRecords()
      this.observer = null
    }
  }
}
</script>

<style lang="stylus" scoped>
.container
  position relative
  .resize-element
    transform translate(-50%, -50%)
    position absolute
    top 50%
    left 50%
    height 10rem
    width 10rem
    overflow hidden
    resize both
    display block
    box-shadow 0 0 1px 1px #3361D8
    border-radius 2px
</style>

  这里记录了旧的宽高数据来避免重复触发回调函数,这样做的原因在于宽高数据改变时,不一定是整数,而MutationRecord.recordOldValue中记录的是取整后的数据,这样就会导致在拖动改变DOM元素的宽高时,数值一直在整数和小数之间跳动,会多次触发。

### 前端 `div` 监听 `resize` 事件 由于标准的 `resize` 事件仅适用于窗口对象,对于特定的 DOM 元素如 `<div>` 并不支持此事件。为了实现对单个 `div` 的尺寸变化监听,可以采用几种不同的策略。 #### 使用 ResizeObserver API 现代浏览器提供了 `ResizeObserver` 接口来观察目标元素的尺寸更改。这允许开发者监控任何元素的内容矩形的变化情况,并相应地作出反应[^4]。 ```javascript const elementToWatch = document.querySelector('#myDiv'); // 创建一个新的 ResizeObserver 实例并定义回调函数 const resizeObserver = new ResizeObserver((entries) => { for (let entry of entries) { console.log('Element resized:', entry.contentRect); } }); // 开始观察指定的目标节点 resizeObserver.observe(elementToWatch); // 如果不再需要观察,则可以通过下面的方法停止观察 // resizeObserver.unobserve(elementToWatch); ``` 这种方法的优势在于它不需要依赖于定时器轮询或其他间接手段就能精确捕捉到元素的实际大小改变。 #### 老版本兼容方案 如果考虑到较旧版浏览器的支持问题,可能无法使用 `ResizeObserver` 。此时可考虑其他替代方式,比如通过检测属性变动或布局更新触发自定义逻辑: 一种常见的做法是在每次页面重绘时检查感兴趣元素的新尺寸并与之前记录下来的值对比;当发现差异时即认为发生了调整行为。不过这种方式效率较低且容易造成性能瓶颈,在实际应用中应谨慎选用。 另一种思路是利用 MutationObserver 来监视 DOM 结构上的变更,虽然这不是直接针对尺寸变化的设计初衷,但在某些场景下也能起到一定作用。 需要注意的是,以上提到的老版本兼容方案并不是最佳实践,推荐尽可能使用最新的 Web 标准特性如 `ResizeObserver` ,除非确实存在跨平台兼容性的严格要求。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值