详解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插件开发之实现google+圈子选择功能
Mar 10 Javascript
JavaScript函数详解
Nov 17 Javascript
基于jquery实现省市联动效果
Nov 23 Javascript
javascript实现的全国省市县无刷新多级关联菜单效果代码
Aug 01 Javascript
基于JavaScript实现鼠标向下滑动加载div的代码
Aug 31 Javascript
AngularJs ng-route路由详解及实例代码
Sep 14 Javascript
Bootstrap轮播插件使用代码
Oct 11 Javascript
Bootstrap select多选下拉框实现代码
Dec 23 Javascript
详解JS去重及字符串奇数位小写转大写
Dec 29 Javascript
BootStrap 获得轮播中的索引和当前活动的焦点对象
May 11 Javascript
详解如何在Node.js的httpServer中接收前端发送的arraybuffer数据
Nov 11 Javascript
vue移动端弹起蒙层滑动禁止底部滑动操作
Jul 22 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
虹吸壶煮咖啡26个注意事项
2021/03/03 冲泡冲煮
通过修改配置真正解决php文件上传大小限制问题(nginx+php)
2015/09/23 PHP
非常强大的 jQuery.AsyncBox 弹出对话框插件
2011/08/29 Javascript
jquery实现仿Flash的横向滑动菜单效果代码
2015/09/17 Javascript
javascript html5移动端轻松实现文件上传
2020/03/27 Javascript
javascript数组去重方法分析
2016/12/15 Javascript
详解Angular的内置过滤器和自定义过滤器【推荐】
2016/12/26 Javascript
jQuery如何跳转到另一个网页 就这么简单
2016/12/28 Javascript
Angularjs中ng-repeat的简单实例
2017/08/25 Javascript
Angularjs添加排序查询功能的实例代码
2017/10/24 Javascript
vue生命周期与钩子函数简单示例
2019/03/13 Javascript
Cordova(ionic)项目实现双击返回键退出应用
2019/09/17 Javascript
Vue插件之滑动验证码
2019/09/21 Javascript
原生js实现弹窗消息动画
2020/11/20 Javascript
基于element-ui封装表单金额输入框的方法示例
2021/01/06 Javascript
详解Python实现多进程异步事件驱动引擎
2017/08/25 Python
PyQt5每天必学之滑块控件QSlider
2018/04/20 Python
python协程之动态添加任务的方法
2019/02/19 Python
python之拟合的实现
2019/07/19 Python
Django 创建/删除用户的示例代码
2019/07/24 Python
Pandas聚合运算和分组运算的实现示例
2019/10/17 Python
python实现发送带附件的邮件代码分享
2020/09/22 Python
python 5个实用的技巧
2020/09/27 Python
Python importlib模块重载使用方法详解
2020/10/13 Python
CSS3 media queries + jQuery实现响应式导航
2016/09/30 HTML / CSS
俄罗斯在线手表和珠宝商店:AllTime
2019/09/28 全球购物
关于Java String的一道面试题
2013/09/29 面试题
高级方案规划工程师岗位职责
2013/11/29 职场文书
校班主任推荐信范文
2013/12/03 职场文书
初中生期末考试的自我评价
2013/12/17 职场文书
老师自我鉴定范文
2013/12/25 职场文书
服装采购员岗位职责
2014/03/15 职场文书
2014年保卫部工作总结
2014/11/21 职场文书
vue实现水波涟漪效果的点击反馈指令
2021/05/31 Vue.js
Python爬虫基础之简单说一下scrapy的框架结构
2021/06/26 Python
springboot实现string转json json里面带数组
2022/06/16 Java/Android