使用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 终止函数执行操作
Feb 14 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
Sep 04 Javascript
AngularJS 2.0入门权威指南
Oct 08 Javascript
Extjs让combobox写起来简洁又漂亮
Jan 05 Javascript
jQuery中each循环的跳出和结束实例
Aug 16 jQuery
浅谈Webpack下多环境配置的思路
Jun 27 Javascript
vue 实现在函数中触发路由跳转的示例
Sep 01 Javascript
React Router V4使用指南(精讲)
Sep 17 Javascript
javascript设计模式之装饰者模式
Jan 30 Javascript
JS实现前端动态分页码代码实例
Jun 02 Javascript
Javascript前端下载后台传来的文件流代码实例
Aug 18 Javascript
浅谈JavaScript作用域
Dec 06 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中的字符串函数
2006/11/24 PHP
PHP中使用array函数新建一个数组
2015/11/19 PHP
zend框架实现支持sql server的操作方法
2016/12/08 PHP
PHP+AJAX 投票器功能
2017/11/11 PHP
PHP实现根据数组某个键值大小进行排序的方法
2018/03/13 PHP
原生JS实现Ajax通过POST方式与PHP进行交互的方法示例
2018/05/12 PHP
如何在PHP中读写文件
2020/09/07 PHP
推荐40个非常优秀的jQuery插件和教程【系列三】
2011/11/09 Javascript
js取消单选按钮选中并判断对象是否为空
2013/11/14 Javascript
改变状态栏文字的js代码
2014/06/13 Javascript
node.js中的path.sep方法使用说明
2014/12/08 Javascript
学习JavaScript正则表达式
2015/11/13 Javascript
JS组件Bootstrap按钮组与下拉按钮详解
2016/05/10 Javascript
jquery实现左右滑动式轮播图
2017/03/02 Javascript
jquery仿微信聊天界面
2017/05/06 jQuery
vue-cli 使用vue-bus来全局控制的实例讲解
2018/09/15 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
Node.js npm命令运行node.js脚本的方法
2018/10/10 Javascript
js中的数组对象排序分析
2018/12/11 Javascript
微信二次分享报错invalid signature问题及解决方法
2019/04/01 Javascript
小程序组件之自定义顶部导航实例
2019/06/12 Javascript
微信小程序日历插件代码实例
2019/12/04 Javascript
js判断浏览器的环境(pc端,移动端,还是微信浏览器)
2020/12/24 Javascript
js 解析 JSON 数据简单示例
2020/04/21 Javascript
python写的一个文本编辑器
2014/01/23 Python
Django自定义过滤器定义与用法示例
2018/03/22 Python
和孩子一起学习python之变量命名规则
2018/05/27 Python
详解在python操作数据库中游标的使用方法
2019/11/12 Python
Python selenium爬取微博数据代码实例
2020/05/22 Python
python爬虫利用selenium实现自动翻页爬取某鱼数据的思路详解
2020/12/22 Python
python函数超时自动退出的实操方法
2020/12/28 Python
教师实习期自我鉴定
2013/10/06 职场文书
网络技术专业求职信
2014/02/18 职场文书
感恩母亲节演讲稿
2014/05/07 职场文书
投标诚信承诺书
2014/05/26 职场文书
演讲稿之感恩老师(三篇范文)
2019/09/06 职场文书