使用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 相关文章推荐
在textarea中屏蔽js的某个function的javascript代码
Apr 20 Javascript
基于jquery的鼠标拖动效果代码
May 30 Javascript
仿当当网淘宝网等主流电子商务网站商品分类导航菜单
Sep 25 Javascript
node.js中的console.dir方法使用说明
Dec 10 Javascript
JQuery勾选指定name的复选框集合并显示的方法
May 18 Javascript
JS从一组数据中找到指定的单条数据的方法
Jun 02 Javascript
一句jQuery代码实现返回顶部效果(简单实用)
Dec 28 Javascript
js正则表达式验证密码强度【推荐】
Mar 03 Javascript
Node.js 的模块知识汇总
Aug 16 Javascript
element-ui upload组件多文件上传的示例代码
Oct 17 Javascript
JavaScript正则表达式验证登录实例
Mar 18 Javascript
canvas多重阴影发光效果实现
Apr 20 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
玩家交还《星际争霸》原始码光盘 暴雪报以厚礼
2017/05/05 星际争霸
php实现读取超大文件的方法
2014/07/28 PHP
PHP生成随机字符串(3种方法)
2015/09/25 PHP
prototype与jquery下Ajax实现的差别
2009/09/13 Javascript
网站繁简切换的JS遇到页面卡死的解决方法
2014/03/12 Javascript
DOM操作一些常用的属性汇总
2015/03/13 Javascript
通过bootstrap全面学习less
2016/11/09 Javascript
微信小程序的动画效果详解
2017/01/18 Javascript
vue.js的手脚架vue-cli项目搭建的步骤
2017/08/30 Javascript
利用vscode调试编译后的js代码详解
2018/05/14 Javascript
jquery.param()实现数组或对象的序列化方法
2018/10/08 jQuery
微信小程序实现分享朋友圈的图片功能示例
2019/01/18 Javascript
微信小程序getLocation 需要在app.json中声明permission字段
2020/03/03 Javascript
Vue Router 实现动态路由和常见问题及解决方法
2020/03/06 Javascript
JavaScript实现复选框全选和取消全选
2020/11/20 Javascript
[55:23]VGJ.T vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python线程中对join方法的运用的教程
2015/04/09 Python
Pytorch入门之mnist分类实例
2018/04/14 Python
python之django母板页面的使用
2018/07/03 Python
用pandas中的DataFrame时选取行或列的方法
2018/07/11 Python
python 进程的几种创建方式详解
2019/08/29 Python
python json load json 数据后出现乱序的解决方案
2020/02/27 Python
python脚本实现mp4中的音频提取并保存在原目录
2020/02/27 Python
python实现最短路径的实例方法
2020/07/19 Python
Python读写压缩文件的方法
2020/07/30 Python
使用PyCharm安装pytest及requests的问题
2020/07/31 Python
阿根廷首家户外用品制造商和经销商:Montagne
2018/02/12 全球购物
手工制作的意大利礼服鞋:Ace Marks
2018/12/15 全球购物
建筑工程毕业生自我鉴定
2014/01/14 职场文书
GMP办公室主任岗位职责
2014/03/14 职场文书
铁路安全事故反思
2014/04/26 职场文书
党的群众路线教育实践活动个人对照检查材料(公安)
2014/11/05 职场文书
2015大学生实训报告
2014/11/05 职场文书
Vertica集成Apache Hudi重磅使用指南
2022/03/31 Servers
Nginx禁止ip访问或非法域名访问
2022/04/07 Servers
Nginx+Tomcat负载均衡多实例详解
2022/04/11 Servers