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


Posted in Javascript onFebruary 24, 2016

起因

今天写页面的时候突然有这么个需求,由于父元素(一个DIV)的height是由javascript计算出来的固定的值,而在其中增加了一个多说插件,在用户评论后,子元素(DIV)的height属性增加,导致子元素溢出。但是又不知道如何为多说的评论按钮增加回调函数,于是乎就想到了根据子元素的大小变化来重新计算父元素的height。

onresize?

平常,都是在整个浏览器窗口变化时触发一个修改布局的回调函数。使用的是window对象的resize事件,利用:

window.onresize = callback;

来绑定。但根据resize事件的target是defaultView (window),这里详见MDN的resize文档,也就是说只有window对象有resize事件,于是乎就想到使用jQuery自己的事件机制来模拟一个普通元素上的resize事件

使用JQUERY事件的实现思路

可以想到一种比较简单的方式:

1. 在元素绑定resize对象时,记录元素的width和height
2. 使用requestAnimationFrame、setTimeout、setInterval,每隔一段时间查询其width和height,如果和记录的width和height不一样,运行回调函数并更新记录中的width为height

JQUERY插件

这个功能Ben Alman编写了一个jQuery插件,传送门
该插件的代码(核心部分),详细代码请查看Ben Alman博客的内容:

(function($, window, undefined) {
 var elems = $([]),
  jq_resize = $.resize = $.extend($.resize, {}),
  timeout_id,
  str_setTimeout = 'setTimeout',
  str_resize = 'resize',
  str_data = str_resize + '-special-event',
  str_delay = 'delay',
  str_throttle = 'throttleWindow';
 jq_resize[str_delay] = 250;
 jq_resize[str_throttle] = true;
 $.event.special[str_resize] = {
  setup: function() {
   if (!jq_resize[str_throttle] && this[str_setTimeout]) {
    return false;
   }
   var elem = $(this);
   elems = elems.add(elem);
   $.data(this, str_data, {
    w: elem.width(),
    h: elem.height()
   });
   if (elems.length === 1) {
    loopy();
   }
  },
  teardown: function() {
   if (!jq_resize[str_throttle] && this[str_setTimeout]) {
    return false;
   }
   var elem = $(this);
   elems = elems.not(elem);
   elem.removeData(str_data);
   if (!elems.length) {
    clearTimeout(timeout_id);
   }
  },
  add: function(handleObj) {
   if (!jq_resize[str_throttle] && this[str_setTimeout]) {
    return false;
   }
   var old_handler;
   function new_handler(e, w, h) {
    var elem = $(this),
     data = $.data(this, str_data);
    data.w = w !== undefined ? w : elem.width();
    data.h = h !== undefined ? h : elem.height();
    old_handler.apply(this, arguments);
   }
   if ($.isFunction(handleObj)) {
    old_handler = handleObj;
    return new_handler;
   } else {
    old_handler = handleObj.handler;
    handleObj.handler = new_handler;
   }
  }
 };

 function loopy() {
  timeout_id = window[str_setTimeout](function() {
   elems.each(function() {
    var elem = $(this),
     width = elem.width(),
     height = elem.height(),
     data = $.data(this, str_data);
    if (width !== data.w || height !== data.h) {
     elem.trigger(str_resize, [data.w = width, data.h = height]);
    }
   });
   loopy();
  }, jq_resize[str_delay]);
 }
})(jQuery, this);

jQuery为jQuery插件的开发者提供了添加自定义事件的接口,详细可以参考jQuery官方文档,这里就是典型的jQuery自定义事件添加方式,其中有三个钩子:

1. setup:The setup hook is called the first time an event of a particular type is attached to an element.首次绑定时执行,如果返回 false,使用默认方式绑定事件
2. teardown:The teardown hook is called when the final event of a particular type is removed from an element.若指定该方法,其在移除事件处理程序(removeEventListener)前执行,如果返回 false,移除默认绑定事件
3. add:Each time an event handler is added to an element through an API such as .on(), jQuery calls this hook.每一次给元素绑定事件,都会执行这个方法

setup、teardown和add三个钩子,每个钩子最先做的事都是检测是否该对象为window对象,然后根据window对象特殊处理,因为window对象本身有resize事件

从setup钩子可以看到,在初始化整个事件处理时,创建一个元素队列,队列中的每隔元素都把width和height放在data中,然后每隔250ms启动loopy函数,在loopy函数中判断是否变化,如果有变,触发回调函数并更新data中的width和height

从teardown钩子可以看到,在元素移除事件时,只需要将元素从元素队列移除,并清除元素中的data数据。如果是元素队列中的最后一个元素,则不再继续执行loopy

add钩子中,对回调函数进行了包装

由此可以看到一个简单的jQuery自定义函数的实现机制

Javascript 相关文章推荐
js类中的公有变量和私有变量
Jul 24 Javascript
jQuery调用RESTful WCF示例代码(GET方法/POST方法)
Jan 26 Javascript
JS嵌套函数调用上下文的问题解决
Mar 26 Javascript
js实现进度条的方法
Feb 13 Javascript
js实现商城星星评分的效果
Dec 29 Javascript
jQuery数据检索中根据关键字快速定位GridView指定行的实现方法
Jun 08 Javascript
jquery删除table当前行的实例代码
Oct 07 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
Jan 20 Javascript
H5图片压缩与上传实例
Apr 21 Javascript
基于aotu.js实现微信自动添加通讯录中的联系人功能
May 28 Javascript
基于原生js实现判断元素是否有指定class名
Jul 11 Javascript
vue 解决在微信内置浏览器中调用支付宝支付的情况
Nov 09 Javascript
JavaScript中的闭包
Feb 24 #Javascript
jQuery中判断对象是否存在的方法汇总
Feb 24 #Javascript
jquery中键盘事件小结
Feb 24 #Javascript
javascript实现九宫格相加数值相等
May 28 #Javascript
Javascript类型转换的规则实例解析
Feb 23 #Javascript
理解Javascript图片预加载
Feb 23 #Javascript
Bootstarp风格的toggle效果分享
Feb 23 #Javascript
You might like
php addslashes及其他清除空格的方法是不安全的
2012/01/25 PHP
解析php中die(),exit(),return的区别
2013/06/20 PHP
PHP反向代理类代码
2014/08/15 PHP
php建立Ftp连接的方法
2015/03/07 PHP
关于JavaScript与HTML的交互事件
2013/04/12 Javascript
JQuery中使用on方法绑定hover事件实例
2014/12/09 Javascript
Java Mybatis框架入门基础教程
2015/09/21 Javascript
在web中js实现类似excel的表格控件
2016/09/01 Javascript
D3.js实现饼状图的方法详解
2016/09/21 Javascript
原生js实现类似fullpage的单页/全屏滚动
2017/01/22 Javascript
微信小程序之滚动视图容器的实现方法
2017/09/26 Javascript
angular写一个列表的选择全选交互组件的示例
2018/01/22 Javascript
微信小程序实现banner图轮播效果
2020/06/28 Javascript
利用webpack理解CommonJS和ES Modules的差异区别
2020/06/16 Javascript
[02:12]Dota 2 推出全新英雄—— 电炎绝手
2019/08/23 DOTA
实例探究Python以并发方式编写高性能端口扫描器的方法
2016/06/14 Python
python虚拟环境的安装配置图文教程
2017/10/20 Python
python爬虫URL重试机制的实现方法(python2.7以及python3.5)
2018/12/18 Python
python 画三维图像 曲面图和散点图的示例
2018/12/29 Python
Python图像处理之gif动态图的解析与合成操作详解
2018/12/30 Python
python抓取需要扫微信登陆页面
2019/04/29 Python
Python Matplotlib绘图基础知识代码解析
2020/08/31 Python
python 使用csv模块读写csv格式文件的示例
2020/12/02 Python
Python制作简单的剪刀石头布游戏
2020/12/10 Python
解决TensorFlow训练模型及保存数量限制的问题
2021/03/03 Python
JINS眼镜官方网站:日本最大的眼镜邮购
2016/10/14 全球购物
Dr. Martens马汀博士官网:马丁靴始祖品牌
2016/10/15 全球购物
kmart凯马特官网:美国最大的打折零售商和全球最大的批发商之一
2016/11/17 全球购物
护理专业毕业生自荐书
2014/05/24 职场文书
县政府领导班子“四风”方面突出问题整改措施
2014/09/23 职场文书
2014年市场部工作总结
2014/11/25 职场文书
社会实践活动报告
2015/02/05 职场文书
2016年国庆节新闻稿范文
2015/11/25 职场文书
导游词之鲁迅祖居
2019/10/17 职场文书
《哪吒之魔童降世》观后感:世上哪有随随便便的成功
2019/11/08 职场文书
HTML中的表单Form实现居中效果
2021/05/25 HTML / CSS