• Jquery揭秘系列:实现 ready和bind事件


    讲这一节之前,先回顾之前的一篇《小谈Jquery》里面的代码:

        (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();
                            }
                        }
                    }
    View Code

    这段代码我之前其实讲过了(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;
                            });
                        }
    
                    }
    View Code

    这里面都是些兼容性代码,实现节点的事件注册。之前的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);
    View Code

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

    如果有疑问或者意见的TX直接留言吧。反正大家是互相学习,互相交流。

     

     

  • 相关阅读:
    Linux 自定义快捷命令
    Linux 用户登陆提示This account is currently not available
    Linux 切换用户提示Permission denied
    Netty核心组件之ChannelPipeline
    Netty核心组件之ChannelHandler
    Netty核心组件之Channel
    Netty核心组件之ChannlFuture
    Error creating bean with name 'eurekaAutoServiceRegistration'
    关于mysql数据库时间与java后台时间类型
    rabbitMQ-helloWorld
  • 原文地址:https://www.cnblogs.com/a546558309/p/3497798.html
Copyright © 2020-2023  润新知