JavaScript监听一个DOM元素大小变化

1.需求场景

开发过程中经常遇到的一个问题就是如何监听一个 div 的size变化。
比如我用canvas绘制了一个chart,当canvas的size发生变化的时候,需要重新绘制里面的内容,这个时候就需要监听resize事件做处理。window上虽然有resize事件监听,但这并不能满足我们的需求,因为很多时候,div的size发生了变化,实际 window.resize 事件并未触发。
对于div的resize事件的监听,实现方式有很多,比如定时器检查,通过scroll事件等等,本文主要介绍通过iframe元素来实现监听。
不过我们可以间接利用window的resize事件监听来实现对于某个div的resize事件监听,请看下面具体实现。

2. 实现原理

  • 动态创建 iframe 标签,追加到容器中,宽高继承容器100%;
  • 获取 iframe 中的window,通过 contentWindow 属性就能获取到;
  • 由于 iframe 的宽高继承与父节点,当父容器宽度发生变化,自然会触发iframe中的resize 事件;

通过 iframeWindow.resize 事件来监听DOM大小变化,从而达到resize事件的一个监听;

例子

document.querySelector("#ifarme_id").contentWindow.addEventListener('resize', () => {
  console.log('size Change!');
}, false)

3.调用

<!DOCTYPE html>
<html>
  <head>
 <meta charset="utf-8">
 <title>DIV宽高监听</title>
  <style type="text/css">
    #content {
    overflow: auto;
  }
 </style>
 </head>
 <body>
 <div id="content">
      钟南山:非洲如果预防得好,天热时疫情会下降
     另外,会上有外籍人士提问:假如你现在去非洲,首先要做的是什么?
     钟南山表示:现在要做的是防护,防止蔓延是最重要的。
     在非洲,这段时间如果预防得好,也可能到天热时,疫情发展情况会下降。
 </div>

 <button id="change-size">改变宽高</button>

 <script type="text/javascript">
  var eleResize = new ElementResize('#content');
  eleResize.listen(function() {
  console.log('size change!')
  })

  //改变宽高
  document.querySelector('#change-size').addEventListener('click', function() {
  let cont = document.querySelector('#content');
  cont.style.width = Math.floor((Math.random() * (document.documentElement.clientWidth - 500)) + 500) + 'px';
  cont.style.height = Math.floor(Math.random() * 300) + 'px';
  }, false)
 </script>
 </body>
</html>

完整代码

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <title>DIV宽高监听</title>
 <style type="text/css">
  #content {
  overflow: auto;
  }
 </style>
 </head>
 <body>
 <div id="content">
  钟南山:非洲如果预防得好,天热时疫情会下降

  另外,会上有外籍人士提问:假如你现在去非洲,首先要做的是什么?

  钟南山表示:现在要做的是防护,防止蔓延是最重要的。

  在非洲,这段时间如果预防得好,也可能到天热时,疫情发展情况会下降。
 </div>
 <button id="change-size">改变宽高</button>

 <script type="text/javascript">
  (function() {
  let self = this;
  /**
   * 元素宽高监听
   * @param {Object} el 监听元素选择器
   */
  function ElementResize(eleSelector) {
   if (!(this instanceof ElementResize)) return;
   if (!eleSelector) return;
   this.eleSelector = eleSelector;
   this.el = document.querySelector(eleSelector);
   this.queue = [];
   this.__init(); //globel init
  }

  //初始化
  ElementResize.prototype.__init = function() {
   let iframe = this.crateIElement();
   this.el.style.position = 'relative';
   this.el.appendChild(iframe)
   this.bindEvent(iframe.contentWindow);
  }

  /**
   * 设置元素样式
   * @param {HTMLObject} el
   * @param {Object} styleJson
   */
  ElementResize.prototype.setStyle = function(el, styleJson) {
   if (!el) return;
   styleJson = styleJson || {
   opacity: 0,
   'z-index': '-1111',
   position: 'absolute',
   left: 0,
   top: 0,
   width: '100%',
   height: '100%',
   };
   let styleText = '';
   for (key in styleJson) {
   styleText += (key + ':' + styleJson[key] + ';');
   }
   el.style.cssText = styleText;
  }

  /**
   * 创建元素
   * @param {Object} style
   */
  ElementResize.prototype.crateIElement = function(style) {
   let iframe = document.createElement('iframe');
   this.setStyle(iframe);
   return iframe;
  }

  /**
   * 绑定事件
   * @param {Object} el
   */
  ElementResize.prototype.bindEvent = function(el) {
   if (!el) return;
   var _self = this;
   el.addEventListener('resize', function() {
   _self.runQueue();
   }, false)
  }

  /**
   * 运行队列
   */
  ElementResize.prototype.runQueue = function() {
   let queue = this.queue;
   for (var i = 0; i < queue.length; i++) {
   (typeof queue[i]) === 'function' && queue[i].apply(this);
   }
  }

  /**
   * 外部监听
   * @param {Object} cb 回调函数
   */
  ElementResize.prototype.listen = function(cb) {
   if (typeof cb !== 'function') throw new TypeError('cb is not a function!');
   this.queue.push(cb);
  }

  self.ElementResize = ElementResize;
  })()

  //创建一个监听实例
  var eleResize = new ElementResize('#content');
  eleResize.listen(function() {
  console.log('我是listener')
  })

  //宽高切换
  document.querySelector('#change-size').addEventListener('click', function() {
  let cont = document.querySelector('#content');
  cont.style.width = Math.floor((Math.random() * (document.documentElement.clientWidth - 500)) + 500) + 'px';
  cont.style.height = Math.floor(Math.random() * 300) + 'px';
  }, false)
 </script>
 </body>
</html>

到此这篇关于JavaScript监听一个DOM元素大小变化的文章就介绍到这了,更多相关JavaScript监听DOM元素大小内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Javascript DOM事件操作小结(监听鼠标点击、释放,悬停、离开等)

    本文实例总结了Javascript DOM事件操作.分享给大家供大家参考,具体如下: 使用JavaScript可以对HTML页面上的各种事件进行监听,如鼠标点击/释放,鼠标悬停/离开,等等. 效果图: 代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> &l

  • JavaScript监听一个DOM元素大小变化

    1.需求场景 开发过程中经常遇到的一个问题就是如何监听一个 div 的size变化. 比如我用canvas绘制了一个chart,当canvas的size发生变化的时候,需要重新绘制里面的内容,这个时候就需要监听resize事件做处理.window上虽然有resize事件监听,但这并不能满足我们的需求,因为很多时候,div的size发生了变化,实际 window.resize 事件并未触发. 对于div的resize事件的监听,实现方式有很多,比如定时器检查,通过scroll事件等等,本文主要介绍

  • 使用jQuery监听DOM元素大小变化

    起因 今天写页面的时候突然有这么个需求,由于父元素(一个DIV)的height是由javascript计算出来的固定的值,而在其中增加了一个多说插件,在用户评论后,子元素(DIV)的height属性增加,导致子元素溢出.但是又不知道如何为多说的评论按钮增加回调函数,于是乎就想到了根据子元素的大小变化来重新计算父元素的height. onresize? 平常,都是在整个浏览器窗口变化时触发一个修改布局的回调函数.使用的是window对象的resize事件,利用: window.onresize =

  • js监听输入框值的即时变化onpropertychange、oninput

    要达到的效果 很多情况下我们都会即时监听输入框值的变化,以便作出即时动作去引导浏览者增强网站的用户体验感.比如即时显示输入框已经被输入的字节数,或者即时读取输入的值来进行搜索引导,也就是google的关联搜索效果等. 只要我们能捕获即时事件就能做到很多事情. 需要了解的知识 首先,我们需要了解onchange和onpropertychange的不同: IE下,当一个HTML元素的属性改变的时候,都能通过 onpropertychange来即时捕获. onchange在属性值改变时还必须使得当前元

  • Java NIO.2 使用Path接口来监听文件、文件夹变化

    Java7对NIO进行了大的改进,新增了许多功能: •对文件系统的访问提供了全面的支持 •提供了基于异步Channel的IO 这些新增的IO功能简称为 NIO.2,依然在java.nio包下. 早期的Java只提供了File类来操作文件.文件夹本身,功能有限,性能也不高. NIO.2为解决这种缺陷,提供了Path接口,并提供了Paths.Files2个工具类,这2个工具类包含的方法都是静态方法,Files类提供了大量的静态方法来操作文件.文件夹. Path接口.Paths工具类使用示例: //获

  • vue中实现监听数组内部元素

    目录 vue监听数组内部元素 我们有两种办法解决此问题 vue如何监听数组的变化 vue监听数组内部元素 在VUE中,对数组的监听是浅监听,也就是它只能监听到数组的长度或者有无的变化,当我们修改数组中的某一个值时,也就是数组的长度状态并没有改变时,在正常情况下它是无法监听到的,在watch中我们知道可以使用deep属性进行深监听,那么在其他情况下呢? 我们有两种办法解决此问题 1.通过原生的js对数组先进行切割,然后在添加新的内容(也就是我们要修改的内容) array.splice(i, 1,

  • Angular中使用$watch监听object属性值的变化(详解)

    Angular中的$watch可以监听属性值的变化,然后并做出相应处理. 常见用法: $scope.$watch("person", function(n, o){ //todo something... }) 但是对于一个对象中的某个属性值变化时,$watch似乎不管用了. 示例代码: <body> <div ng-controller="mainCtrl"> <input id="myText" type=&qu

  • 微信小程序在其他页面监听globalData中值的变化

    前言 这几天去面试,多次碰到同一个知识点.而且有一次面试挺有趣的,是关于小程序的.共有3个问题. 1.小程序中Page.watch()方法是做什么用的? 2.小程序中如何在其他页面中监听到globalData中值的变化? 3.如果在app.js执行登录部分的代码,由于时序问题,如何处理其他页面请求时未获取到身份识别标记的情况.(session,userid等).(大意是:怎么能够保证其他页面请求是在登录之后?) 知识点 有经验的同学可能一下子就看出来了,这其实说的是同一个东西,那就是Object

  • 解决layui下拉框监听问题(监听不到值的变化)

    关于layui监听下拉框值得变化,大家都知道官方文档给我们提供了一个方法 form.on('select(demo)',function(data){ console.log(data.value)//打印当前select选中的值 }) 按照我之前的理解,监听下拉框值得变化,就是只有下拉框的值发生了改变,才会触发这个事件,否则就不触发.但是这个方法是,只要你鼠标点击了下拉选项里面的值,不论这个值跟之前的值是否相等,都会触发这个事件. 下面说一下我的解决办法 1.首先,我写了一个input框,用来

  • vue项目如何监听localStorage或sessionStorage的变化

    出现这个问题的起因:在一个VUE页面中,引入两个组件,A组件实现基础信息展示,B组件展示列表,我要通过A组件的一个按钮触发状态,然后B组件根据A组件触发的状态来做业务处理,首先想到的是把状态放在localStorage,接下去就是在B组件怎么监听A组件状态 解决方法: 1.首先在 main.js 中给 Vue.protorype 注册一个全局方法,然后创建一个 StorageEvent 方法,当我在执行sessionStorage.setItem(k, val) 的时候,初始化事件并派发事件.

  • Vue子组件监听父组件值的变化

    目录 子组件监听父组件值变化 子组件监听父组件的值同步更新数据 子组件监听父组件值变化 子组件中利用watch监听父组件值的变化 // 子组件 props: ["a"],     watch: {         a(oldValue, newValue) {             // oldValue  a旧值             // newValue a新值         }     } 子组件监听父组件的值同步更新数据 子组件 props : ["data&

随机推荐