使用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中的关键字"VAR"使用详解 分享
Jul 31 Javascript
一个js导致的jquery失效问题的解决方法
Nov 27 Javascript
JavaScript的Backbone.js框架环境搭建及Hellow world示例
May 07 Javascript
jquery表单插件Autotab使用方法详解
Jun 24 Javascript
JS搜狐面试题分析
Dec 16 Javascript
Web前端框架bootstrap实战【第一次接触使用】
Dec 28 Javascript
Vuex之理解Store的用法
Apr 19 Javascript
JavaScript异步加载问题总结
Feb 17 Javascript
JavaScript实现点击出现图片并统计点击次数功能示例
Jul 23 Javascript
解决vuex刷新状态初始化的方法实现
Aug 15 Javascript
vue.js自定义组件实现v-model双向数据绑定的示例代码
Jan 08 Javascript
解决vue刷新页面以后丢失store的数据问题
Aug 11 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 curl模拟post请求和提交多维数组的示例代码
2015/11/19 PHP
几个常用的JavaScript字符串处理函数 - split()、join()、substring()和indexOf()
2009/06/02 Javascript
return false;和e.preventDefault();的区别
2010/07/11 Javascript
Js获取事件对象代码
2010/08/05 Javascript
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
javascript 获取网页标题代码实例
2014/01/22 Javascript
深入理解JavaScript系列(49):Function模式(上篇)
2015/03/04 Javascript
canvas 实现中国象棋
2017/02/17 Javascript
js中的触发事件对象event.srcElement与event.target详解
2017/03/15 Javascript
ExtJs异步无法向外传值和赋值的完美解决办法
2017/06/14 Javascript
微信小程序实现YDUI的ScrollTab组件
2018/02/02 Javascript
vue 实现搜索的结果页面支持全选与取消全选功能
2019/05/10 Javascript
jquery实现简单每周轮换的日历
2020/09/10 jQuery
[02:03]《现实生活中的DOTA2》—林书豪&DOTA2职业选手出演短片
2015/08/18 DOTA
python遍历文件夹并删除特定格式文件的示例
2014/03/05 Python
python字典的常用操作方法小结
2016/05/16 Python
python实现批量解析邮件并下载附件
2018/06/19 Python
Flask框架配置与调试操作示例
2018/07/23 Python
django项目搭建与Session使用详解
2018/10/10 Python
Python常用爬虫代码总结方便查询
2019/02/25 Python
解决django框架model中外键不落实到数据库问题
2020/05/20 Python
Django+Celery实现动态配置定时任务的方法示例
2020/05/26 Python
python爬虫爬取某网站视频的示例代码
2021/02/20 Python
HTML5仿手机微信聊天界面
2016/03/18 HTML / CSS
使用HTML5 Canvas为图片填充颜色和纹理的教程
2016/03/21 HTML / CSS
软件测试题目
2013/02/27 面试题
航空大学应届生求职信
2013/11/10 职场文书
艾滋病宣传活动总结
2014/05/08 职场文书
2014年中秋寄语
2014/08/11 职场文书
2014年销售助理工作总结
2014/12/01 职场文书
2015欢度元旦标语口号
2014/12/09 职场文书
2015年信访工作总结
2015/04/07 职场文书
又涨知识了,自律到底多重要?
2019/06/27 职场文书
委托开发合同书(标准版)
2019/08/07 职场文书
【海涛解说】史上最给力比赛,挑战DOTA极限
2022/04/01 DOTA
详解Redis的三种常用的缓存读写策略步骤
2022/05/06 Redis