使用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 相关文章推荐
常见效果实现之返回顶部(结合淡入、淡出、减速滚动)
Jan 04 Javascript
js禁止document element对象选中文本实现代码
Mar 21 Javascript
网页下载文件期间如何防止用户对网页进行其他操作
Jun 27 Javascript
js中iframe调用父页面的方法
Oct 30 Javascript
javascript图片延迟加载实现方法及思路
Dec 31 Javascript
下雪了 javascript实现雪花飞舞
Aug 02 Javascript
jquery点击改变class并toggle的实现代码
May 15 Javascript
easyui 中的datagrid跨页勾选问题的实现方法
Jan 18 Javascript
JS实现去除数组中重复json的方法示例
Dec 21 Javascript
JavaScript字符串转数字的5种方法及遇到的坑
Jul 16 Javascript
javascript如何实现create方法
Nov 04 Javascript
一文带你理解vue创建一个后台管理系统流程(Vue+Element)
May 18 Vue.js
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实现ASCII码与字符串相互转换的方法
2017/04/29 PHP
PHP多线程模拟实现秒杀抢单
2018/02/07 PHP
基于Jquery的回车成tab焦点切换效果代码(Enter To Tab )
2010/11/14 Javascript
jQuery中 noConflict() 方法使用
2013/04/25 Javascript
Jquery easyUI 更新行示例
2014/03/06 Javascript
JS 新增Cookie 取cookie值 删除cookie 举例详解
2014/10/10 Javascript
JavaScript实现模仿桌面窗口的方法
2015/07/18 Javascript
window.onerror()的用法与实例分析
2016/01/27 Javascript
JavaScript实现经典排序算法之插入排序
2016/12/28 Javascript
详解使用VUE搭建后台管理系统(vue-cli更新至3.0)
2018/08/22 Javascript
ES6 Symbol数据类型的应用实例分析
2019/06/26 Javascript
layer弹窗在键盘按回车将反复刷新的实现方法
2019/09/25 Javascript
关于angular浏览器兼容性问题的解决方案
2020/07/26 Javascript
Python的ORM框架SQLObject入门实例
2014/04/28 Python
python的tkinter布局之简单的聊天窗口实现方法
2014/09/03 Python
python实现redis三种cas事务操作
2017/12/19 Python
基于Python实现的微信好友数据分析
2018/02/26 Python
Python基于FTP模块实现ftp文件上传操作示例
2018/04/23 Python
基于python的图片修复程序(实现水印去除)
2018/06/04 Python
python代码 FTP备份交换机配置脚本实例解析
2019/08/01 Python
Python print不能立即打印的解决方式
2020/02/19 Python
Python中os模块功能与用法详解
2020/02/26 Python
html+css3实现的登录界面
2020/12/09 HTML / CSS
英国羊绒服装购物网站:Pure Collection
2018/10/22 全球购物
激光脱毛、蓝光和护肤:Tria Beauty
2019/03/28 全球购物
请写出 BOOL flag 与"零值"比较的 if 语句
2016/02/29 面试题
JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
2013/07/02 面试题
后勤人员自我评价怎么写
2013/09/19 职场文书
毕业生简单求职信
2013/11/19 职场文书
大学新生军训方案
2014/05/03 职场文书
学生党员批评与自我批评
2014/10/15 职场文书
2014年学校法制宣传日活动总结
2014/11/01 职场文书
检讨书范文500字
2015/01/28 职场文书
财务部岗位职责范本
2015/04/14 职场文书
公司车队管理制度
2015/08/04 职场文书
浅谈Laravel中使用Slack进行异常通知
2021/05/29 PHP