使用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 相关文章推荐
Jquery 1.42 checkbox 全选和反选代码
Mar 27 Javascript
filters.revealTrans.Transition使用方法小结
Aug 19 Javascript
关于jQuery参考实例2.0 用jQuery选择元素
Apr 07 Javascript
javascript在myeclipse中报错的解决方法
Oct 29 Javascript
js实现的牛顿摆效果
Mar 31 Javascript
javascript中setInterval的用法
Jul 19 Javascript
JavaScript提升性能的常用技巧总结【经典】
Jun 20 Javascript
jQuery EasyUI基础教程之EasyUI常用组件(推荐)
Jul 15 Javascript
微信小程序系列之自定义顶部导航功能
May 21 Javascript
Vue 设置axios请求格式为form-data的操作步骤
Oct 29 Javascript
vue实现自定义多选按钮
Jul 16 Javascript
详解如何在Canvas中添加事件的方法
Apr 17 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
phpBB BBcode处理的漏洞
2006/10/09 PHP
ThinkPHP实现支付宝接口功能实例
2014/12/02 PHP
Laravel中log无法写入问题的解决
2017/06/17 PHP
Windows下wamp php单元测试工具PHPUnit安装及生成日志文件配置方法
2018/05/28 PHP
ThinkPHP框架实现的微信支付接口开发完整示例
2019/04/10 PHP
php学习笔记之字符串常见操作总结
2019/07/16 PHP
laravel admin实现分类树/模型树的示例代码
2020/06/10 PHP
打造基于jQuery的高性能TreeView(asp.net)
2011/02/23 Javascript
判断对象是否Window的实现代码
2012/01/10 Javascript
js验证输入是否为手机号码或电话号码示例
2013/12/30 Javascript
javascript实现动态模态绑定grid过程代码
2014/09/22 Javascript
JS全局变量和局部变量最新解析
2016/06/24 Javascript
JavaScript 节流函数 Throttle 详解
2016/07/04 Javascript
AngularJS下对数组的对比分析
2016/08/24 Javascript
Boostrap基础教程之JavaScript插件篇
2016/09/08 Javascript
编写React组件项目实践分析
2018/03/04 Javascript
jQuery+Datatables实现表格批量删除功能【推荐】
2018/10/24 jQuery
使用原生js编写一个简单的框选功能方法
2019/05/13 Javascript
Layui之table中的radio在切换分页时无法记住选中状态的解决方法
2019/09/02 Javascript
[06:13]DOTA2进化论(修改版)
2013/10/08 DOTA
[43:53]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第三场 8.22
2019/09/05 DOTA
Python 深入理解yield
2008/09/06 Python
Python找出9个连续的空闲端口
2016/02/01 Python
Python调用adb命令实现对多台设备同时进行reboot的方法
2018/10/15 Python
Selenium chrome配置代理Python版的方法
2018/11/29 Python
Python基于Logistic回归建模计算某银行在降低贷款拖欠率的数据示例
2019/01/23 Python
python实现连连看辅助(图像识别)
2020/03/25 Python
python多环境切换及pyenv使用过程详解
2019/09/27 Python
使用Django的JsonResponse返回数据的实现
2021/01/15 Python
英国赛车、汽车改装和摩托车零件购物网站:Demon Tweeks
2018/10/29 全球购物
如何掌握自荐信格式呢
2013/11/19 职场文书
青年创业培训欢迎词
2014/01/10 职场文书
销售行政专员岗位职责
2014/06/10 职场文书
你为什么是穷人?可能是这5个缺点造成
2019/07/11 职场文书
Python爬虫实战之爬取京东商品数据并实实现数据可视化
2021/06/07 Python
Mysql InnoDB 的内存逻辑架构
2022/05/06 MySQL