使用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 相关文章推荐
JavaScript高级程序设计
Dec 29 Javascript
vs2003 js文件编码问题的解决方法
Mar 20 Javascript
jquery如何通过name名称获取当前name的value值
Dec 20 Javascript
angularJS 中$scope方法使用指南
Feb 09 Javascript
jQuery实现图片加载完成后改变图片大小的方法
Mar 29 Javascript
JavaScript实现页面跳转的方式汇总
May 16 Javascript
js实现的光标位置工具函数示例
Oct 03 Javascript
vue登录路由验证的实现
Dec 13 Javascript
详解Angularjs 自定义指令中的数据绑定
Jul 19 Javascript
vue自定义js图片碎片轮播图切换效果的实现代码
Apr 28 Javascript
gulp构建小程序的方法步骤
May 31 Javascript
简单了解微信小程序 e.target与e.currentTarget的不同
Sep 27 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不使用插件导出excel的简单方法
2014/03/04 PHP
php cookie中点号(句号)自动转为下划线问题
2014/10/21 PHP
基于ThinkPHP实现批量删除
2015/12/18 PHP
PHP面向对象程序设计方法实例详解
2016/12/24 PHP
Laravel用户授权系统的使用方法示例
2018/09/16 PHP
laravel-admin select框默认选中的方法
2019/10/03 PHP
Prototype使用指南之hash.js
2007/01/10 Javascript
推荐dojo学习笔记
2007/03/24 Javascript
解决extjs在firefox中关闭窗口再打开后iframe中js函数访问不到的问题
2008/11/06 Javascript
javascript 面向对象编程基础 多态
2009/08/21 Javascript
JS实现时间格式化的方式汇总
2013/10/16 Javascript
AngularJS基础 ng-mousemove 指令简单示例
2016/08/02 Javascript
Boostrap基础教程之JavaScript插件篇
2016/09/08 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
Vue异步组件使用详解
2017/04/08 Javascript
67 个节约开发时间的前端开发者的工具、库和资源
2017/09/12 Javascript
五步轻松实现zTree的使用
2017/11/01 Javascript
Angular6 写一个简单的Select组件示例
2018/08/20 Javascript
详解vue2.0模拟后台json数据
2019/05/16 Javascript
Vue 用Vant实现时间选择器的示例代码
2019/10/25 Javascript
Python数据类型详解(一)字符串
2016/05/08 Python
Python实现登陆文件验证方法
2018/10/06 Python
浅谈numpy生成数组的零值问题
2018/11/12 Python
python 实现快速生成连续、随机字母列表
2019/11/28 Python
keras做CNN的训练误差loss的下降操作
2020/06/22 Python
python批量处理多DNS多域名的nslookup解析实现
2020/06/28 Python
加拿大时装零售商:Influence U
2018/12/22 全球购物
金融专业大学生职业生涯规划范文
2014/01/16 职场文书
优秀广告词大全
2014/03/19 职场文书
《桥》教学反思
2014/04/09 职场文书
优秀党支部书记事迹材料
2014/05/29 职场文书
2014年计生工作总结
2014/11/21 职场文书
故意伤害罪辩护词
2015/05/21 职场文书
《怀念母亲》教学反思
2016/02/19 职场文书
2016五四青年节活动总结范文
2016/04/06 职场文书
详细谈谈MYSQL中的COLLATE是什么
2021/06/11 MySQL