详解Jquery实现ready和bind事件


Posted in Javascript onApril 14, 2016

讲这一节之前,先回顾之前一段代码:

(function (win) {
      var _$ = function (selector, context) {
        return new _$.prototype.Init(selector, context);
      }
      _$.prototype = {
        Init: function (selector, context) {
          this.elements = [];
          var context = context || document;
          if (context.querySelectorAll) {
            var arr = context.querySelectorAll(selector);
            for (var i = 0; i < arr.length; i++) {
              this.elements.push(arr[i]);
            }
          }
          ////这一块是选择器的实现,没有写完,可以自己实现
        },
        each: function (callback) {
          if (this.elements.length > 0) {
            for (var i = 0; i < this.elements.length; i++) {
              callback.call(this, i, this.elements[i]);
            }
          }
        }
      }
      _$.prototype.Init.prototype = _$.prototype;
      window.$ = _$;
    })(window || global);

上面我们实现了节点的查找,今天要讲的是对节点的事件绑定。

熟悉Jquery 源码的TX应该知道:我们上面的代码少了ready事件,只是针对节点进行查询,并没有将document对象考虑进去。我之前单独讲过window.onload和 document. ready的区别,还对document.ready事件进行了扩展。

现在我们把扩展方法加到这里面:

我们的Init方法要改正一下:

Init: function (selector, context) {
          this.elements = [];
          if (typeof selector === "function") {
            this.elements.push(document);
            this.ready(selector);
          }
          else {
            var context = context || document;
            var isDocument = function (ele) {
              var tostring = Object.prototype.toString;
              return tostring.call(ele) == "[object HTMLDocument]" || "[object Document]";
            }
            if (isDocument(selector)) {
              this.elements.push(selector);
            }
            else if (context.querySelectorAll) {
              var arr = context.querySelectorAll(selector);
              for (var i = 0; i < arr.length; i++) {
                this.elements.push(arr[i]);
              }
            }
          }
        }

这段代码的大致意思是:如果传入的参数selector是function类型,就执行ready事件。如果是document就将document对象插入到this.elements数组里面(这个传入之后,会在ready事件里面进行判断)。如果是字符窜,就查询出节点,循环插入到this.elements数组里面,没什么难度。主要考虑到$(document).ready和$(function(){})这两种ready事件的写法。

我们接下来把ready函数加进来:

ready: function (callback) {
          var isDocument = function (ele) {
            var tostring = Object.prototype.toString;
            return tostring.call(ele) == "[object HTMLDocument]" | "[object Document]";
          }
          if (isDocument(this.elements[0])) {
            if (document.addEventListener) {
              document.addEventListener('DOMContentLoaded', function () {
                document.removeEventListener('DOMContentLoaded', arguments.callee, false);
                callback();
              }, false);
            }
            else if (document.attachEvent) {
              document.attachEvent('onreadystatechange', function () {
                if (document.readyState == "complete") {
                  document.detachEvent('onreadystatechange', arguments.callee);
                  callback();
                }
              });
            }
            else if (document.lastChild == document.body) {
              callback();
            }
          }
        }

这段代码我之前其实讲过了(onload和ready的区别),不知道的可以看看。

现在ready事件,我们实现了。然后就可以针对节点进行事件注册了。

我们来实现bind函数,代码如下:

bind: function (type, callback) {
          if (document.addEventListener) {
            this.each(function (i, item) {
              item.addEventListener(type, callback, false);
            });
          }
          else if (document.attachEvent) {
            this.each(function (i, item) {
              item.attachEvent('on' + type, callback);
            });
          }
          else {
            this.each(function (i, item) {
              tem['on' + type] = callback;
            });
          }

        }

这里面都是些兼容性代码,实现节点的事件注册。之前的each,大家可能不知道是要干嘛的。现在在这里面就用到了。

主要作用是针对节点循环做一些操作。

完整代码,来一份:

(function (win) {
      var _$ = function (selector, context) {
        return new _$.prototype.Init(selector, context);
      }
      _$.prototype = {
        Init: function (selector, context) {
          this.elements = [];
          if (typeof selector === "function") {
            this.elements.push(document);
            this.ready(selector);
          }
          else {
            var context = context || document;
            var isDocument = function (ele) {
              var tostring = Object.prototype.toString;
              return tostring.call(ele) == "[object HTMLDocument]" | "[object Document]";
            }
            if (isDocument(selector)) {
              this.elements.push(selector);
            }
            else if (context.querySelectorAll) {
              var arr = context.querySelectorAll(selector);
              for (var i = 0; i < arr.length; i++) {
                this.elements.push(arr[i]);
              }
            }
          }
        },
        each: function (callback) {
          var length = this.elements.length;
          if (length > 0) {
            for (var i = 0; i < length; i++) {
              callback.call(this, i, this.elements[i]);
            }
          }
        },
        ready: function (callback) {
          var isDocument = function (ele) {
            var tostring = Object.prototype.toString;
            return tostring.call(ele) == "[object HTMLDocument]" | "[object Document]";
          }
          if (isDocument(this.elements[0])) {
            if (document.addEventListener) {
              document.addEventListener('DOMContentLoaded', function () {
                document.removeEventListener('DOMContentLoaded', arguments.callee, false);
                callback();
              }, false);
            }
            else if (document.attachEvent) {
              document.attachEvent('onreadystatechange', function () {
                if (document.readyState == "complete") {
                  document.detachEvent('onreadystatechange', arguments.callee);
                  callback();
                }
              });
            }
            else if (document.lastChild == document.body) {
              callback();
            }
          }
        },
        bind: function (type, callback) {
          if (document.addEventListener) {
            this.each(function (i, item) {
              item.addEventListener(type, callback, false);
            });
          }
          else if (document.attachEvent) {
            this.each(function (i, item) {
              item.attachEvent('on' + type, callback);
            });
          }
          else {
            this.each(function (i, item) {
              tem['on' + type] = callback;
            });
          }

        }
      }
      _$.prototype.Init.prototype = _$.prototype;
      window.$ = _$;
    })(window);

这几个函数基本上可以实现对节点的事件注册了。其余的一些特效,还需要扩展。如果感兴趣的话可以自己在  _$.prototype对象里面加方法。

以上就是本文的全部内容,希望能够帮助大家。

Javascript 相关文章推荐
基于jQuery和CSS3制作数字时钟附源码下载(jquery篇)
Nov 24 Javascript
Bootstrap每天必学之级联下拉菜单
Mar 27 Javascript
深入浅析Extjs中store分组功能的使用方法
Apr 20 Javascript
JavaScript 对象字面量讲解
Jun 06 Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
Jul 13 Javascript
JavaScript数据类型的存储方法详解
Aug 25 Javascript
js实现随机点名系统(实例讲解)
Oct 18 Javascript
浅析vue 函数配置项watch及函数 $watch 源码分享
Nov 22 Javascript
详解小程序input框失焦事件在提交事件前的处理
May 05 Javascript
js常见遍历操作小结
Jun 06 Javascript
帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
Aug 23 Javascript
vue列表数据发生变化指令没有更新问题及解决方法
Jan 16 Javascript
一起学写js Calender日历控件
Apr 14 #Javascript
jQuery获取父元素节点、子元素节点及兄弟元素节点的方法
Apr 14 #Javascript
原生js实现autocomplete插件
Apr 14 #Javascript
jQuery循环遍历子节点并获取值的方法
Apr 14 #Javascript
基于jQuery实现音乐播放试听列表
Apr 14 #Javascript
js仿3366小游戏选字游戏
Apr 14 #Javascript
Javascript实现鼠标框选操作  不是点击选取
Apr 14 #Javascript
You might like
php smarty 二级分类代码和模版循环例子
2011/06/16 PHP
解析PHP工厂模式的好处
2013/06/18 PHP
php获得用户ip地址的比较不错的方法
2014/02/08 PHP
kohana框架上传文件验证规则写法示例
2014/07/14 PHP
Yii中使用PHPExcel导出Excel的方法
2014/12/26 PHP
Symfony2学习笔记之模板用法详解
2016/03/17 PHP
PHP Beanstalkd消息队列的安装与使用方法实例详解
2020/02/21 PHP
javaScript复制功能调用实现方案
2012/12/13 Javascript
javascript实现俄罗斯方块游戏的思路和方法
2015/04/27 Javascript
基于jquery实现动态竖向柱状条特效
2016/02/12 Javascript
清除浏览器缓存的几种方法总结(必看)
2016/12/09 Javascript
JS基于贪心算法解决背包问题示例
2017/11/27 Javascript
[02:29]DOTA2英雄基础教程 陈
2013/12/17 DOTA
[01:45]典藏宝瓶2+祈求者身心——这就是DOTA2TI9总奖金突破3000万美元的秘密
2019/07/21 DOTA
Python2.7简单连接与操作MySQL的方法
2016/04/27 Python
Python初学者需要注意的事项小结(python2与python3)
2018/09/26 Python
浅谈pycharm出现卡顿的解决方法
2018/12/03 Python
Python 多线程不加锁分块读取文件的方法
2018/12/11 Python
python hough变换检测直线的实现方法
2019/07/12 Python
Django REST framework 如何实现内置访问频率控制
2019/07/23 Python
Pycharm远程连接服务器并实现代码同步上传更新功能
2020/02/25 Python
Python callable内置函数原理解析
2020/03/05 Python
Django media static外部访问Django中的图片设置教程
2020/04/07 Python
css3实现圆锥渐变conic-gradient效果
2020/02/12 HTML / CSS
CSS 3.0文字悬停跳动特效代码
2020/10/26 HTML / CSS
在线学习西班牙语、法语或其他语言:Babbel.com
2018/02/07 全球购物
购买英国原创艺术:Art Gallery
2018/08/25 全球购物
List, Set, Map是否继承自Collection接口?
2016/05/16 面试题
上海中网科技笔试题
2012/02/19 面试题
学年自我鉴定
2014/01/16 职场文书
社会实践活动总结范文
2014/07/03 职场文书
元旦晚会活动总结
2014/07/09 职场文书
党的群众路线对照检查材料
2014/09/22 职场文书
为什么中国式养孩子很累?
2019/08/07 职场文书
导游词之安徽九华山
2019/09/18 职场文书
Win11怎么解除儿童账号限制?Win11解除微软儿童账号限制方法
2022/07/07 数码科技