使用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上传前预览图片实例
Mar 25 Javascript
javascript新建标签,判断键盘输入,以及判断焦点(示例代码)
Nov 25 Javascript
js菜单点击显示或隐藏效果的简单实例
Jan 13 Javascript
jQuery中is()方法用法实例
Jan 06 Javascript
浅谈EasyUI中编辑treegrid的方法
Mar 01 Javascript
javascript汉字拼音互转的简单实例
Oct 09 Javascript
微信小程序 vidao实现视频播放和弹幕的功能
Nov 02 Javascript
Bootstrap按钮组实例详解
Jul 03 Javascript
JavaScript中一些特殊的字符运算
Aug 17 Javascript
解决Vue调用springboot接口403跨域问题
Sep 02 Javascript
JavaScript 浏览器对象模型BOM原理与常见用法实例分析
Dec 16 Javascript
vue cli4.0项目引入typescript的方法
Jul 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
PHP设计模式之代理模式的深入解析
2013/06/13 PHP
PHP实现视频文件上传完整实例
2014/08/28 PHP
无需数据库在线投票调查php代码
2016/07/20 PHP
thinkphp隐藏index.php/home并允许访问其他模块的实现方法
2016/10/13 PHP
浅谈PHP中关于foreach使用引用变量的坑
2016/11/14 PHP
基于 Swoole 的微信扫码登录功能实现代码
2018/01/15 PHP
laravel框架创建授权策略实例分析
2019/11/22 PHP
用javascript操作xml
2006/11/04 Javascript
Jquery Ajax学习实例5 向WebService发出请求,返回泛型集合数据的异步调用
2010/03/17 Javascript
很棒的学习jQuery的12个网站推荐
2011/04/28 Javascript
jQuery中delegate和on的用法与区别详细解析
2014/01/26 Javascript
JavaScript如何实现在文本框(密码框)输入提示语
2015/12/25 Javascript
jQuery设置聚焦并使光标位置在文字最后的实现方法
2016/08/02 Javascript
Javascript Function.prototype.bind详细分析
2016/12/29 Javascript
jQuery插件MovingBoxes实现左右滑动中间放大图片效果
2017/02/28 Javascript
使用js获取伪元素的content实例
2017/10/24 Javascript
webpack的CSS加载器的使用
2018/09/11 Javascript
详解JS浏览器事件循环机制
2019/03/27 Javascript
Python中使用OpenCV库来进行简单的气象学遥感影像计算
2016/02/19 Python
Python IDLE 错误:IDLE''s subprocess didn''t make connection 的解决方案
2017/02/13 Python
python select.select模块通信全过程解析
2017/09/20 Python
Python图片的横坐标汉字实例
2019/12/04 Python
keras 使用Lambda 快速新建层 添加多个参数操作
2020/06/10 Python
python opencv实现直线检测并测出倾斜角度(附源码+注释)
2020/12/31 Python
迪卡侬荷兰官网:Decathlon荷兰
2017/10/29 全球购物
英国家喻户晓的高街品牌:River Island
2017/11/28 全球购物
高分子材料与工程专业推荐信
2013/12/01 职场文书
一年级语文教学反思
2014/02/13 职场文书
工伤事故赔偿协议书(标准)
2014/09/29 职场文书
群众对十八届四中全会的期盼
2014/10/17 职场文书
“爱眼护眼,提前预防近视”倡议书3篇
2019/10/30 职场文书
几款流行的HTML5 UI框架比较(小结)
2021/04/08 HTML / CSS
golang内置函数len的小技巧
2021/07/25 Golang
MySQL非空约束(not null)案例讲解
2021/08/23 MySQL
解析python中的jsonpath 提取器
2022/01/18 Python
python高温预警数据获取实例
2022/07/23 Python