使用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 相关文章推荐
单独使用CKFinder选择图片的方法
Aug 21 Javascript
javascript 函数参数限制说明
Nov 19 Javascript
Bootstrap 折叠(Collapse)插件用法实例详解
Jun 01 Javascript
详解JavaScript中js对象与JSON格式字符串的相互转换
Feb 14 Javascript
vue组件中点击按钮后修改输入框的状态实例代码
Apr 14 Javascript
Bootstrap table使用方法汇总
Nov 17 Javascript
利用js实现前后台传送Json的示例代码
Mar 29 Javascript
详解一个基于套接字实现长连接的express
Mar 28 Javascript
JavaScript中BOM对象原理与用法分析
Jul 09 Javascript
JS实现电脑虚拟键盘打字测试
Jun 24 Javascript
解决removeEventListener 无法清除监听的问题
Oct 30 Javascript
在HTML中使用JavaScript的两种方法
Dec 24 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/30 PHP
php不用正则验证真假身份证
2013/11/06 PHP
ThinkPHP分页类使用详解
2014/03/05 PHP
PHP编写RESTful接口
2016/02/23 PHP
PHP实现数组转JSon和JSon转数组的方法示例
2018/06/14 PHP
PHP网站常见安全漏洞,及相应防范措施总结
2021/03/01 PHP
jQuery中fadeIn、fadeOut、fadeTo的使用方法(图片显示与隐藏)
2013/05/08 Javascript
js实现目录定位正文示例
2013/11/14 Javascript
分享一个自己动手写的jQuery分页插件
2014/08/28 Javascript
AngularJS 2.0新特性有哪些
2016/02/18 Javascript
js实现文字滚动效果
2016/03/03 Javascript
第二次聊一聊JS require.js模块化工具的基础知识
2016/04/17 Javascript
浅析jQuery 遍历函数,javascript中的each遍历
2016/05/25 Javascript
nodejs简单实现操作arduino
2016/09/25 NodeJs
vue获取元素宽、高、距离左边距离,右,上距离等还有XY坐标轴的方法
2018/09/05 Javascript
Vue实现类似Spring官网图片滑动效果方法
2019/03/01 Javascript
vuex 动态注册方法 registerModule的实现
2019/07/03 Javascript
Vue实现按钮级权限方案
2019/11/21 Javascript
使用uni-app开发微信小程序的实现
2019/12/13 Javascript
基于JavaScript实现贪吃蛇游戏
2020/03/16 Javascript
基于Vue CSR的微前端实现方案实践
2020/05/27 Javascript
Vue实现移动端拖拽交换位置
2020/07/29 Javascript
python爬虫 使用真实浏览器打开网页的两种方法总结
2018/04/21 Python
简单了解Python matplotlib线的属性
2019/06/29 Python
django使用admin站点上传图片的实例
2019/07/28 Python
Python3简单爬虫抓取网页图片代码实例
2019/08/26 Python
numpy数组做图片拼接的实现(concatenate、vstack、hstack)
2019/11/08 Python
详解BeautifulSoup获取特定标签下内容的方法
2020/12/07 Python
使用phonegap查找联系人的实现方法
2017/03/31 HTML / CSS
全球地下的服装和态度:Slam Jam
2018/02/04 全球购物
为您的家、后院、车库等在线购物:Spreetail
2019/06/17 全球购物
公安局副政委班子个人对照检查材料
2014/10/04 职场文书
加强机关作风建设心得体会
2014/10/22 职场文书
小程序实现悬浮按钮的全过程记录
2021/10/16 HTML / CSS
攻略丨滑雪究竟该选哪款对讲机?
2022/02/18 无线电
MySQL外键约束(Foreign Key)案例详解
2022/06/28 MySQL