案例展示:模拟jQuery

/**
 * @name:模拟jQuery
 * @time:2019年10月23日23:03:41
 * @author:Hongfei
 */
(function (win) {//自封闭,自己调用自己
    //这是jQuery的工厂
    function jQuery(selector) {
        //init才是jQuery真正的构造函数
        return new jQuery.fn.init(selector);
    };
    //然后给jQuery做了原型替换
    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        version: '1.0.0',
        each: function (collback) {
            jQuery.each(this, callback); //调用静态的each,实现实例each方法
        },
        toArry: function () {
            return [].slice.call(this);
        },
        get: function (index) {
            if (index == undefined || index == null) { //没有传参,或者传过来的参数是null,那么就把jQuery身上挂载的所有dom元素,组织成一个数组返回
                return this.toArry();
            } else if (index >= 0 && index < this.length) { //索引是在正常范围内
                return this[index];
            } else if (index >= -(this.length - 1) && index < 0) {
                return this[this.length + index];
            } else {
                return undefined;
            }
        }
    };
    //核心代码
    //后边所有的功能代码,绝大多数都是通过extend扩展到对象身上的,以此来实现模块化
    jQuery.extend = jQuery.fn.extend = function (obj) {
        for (var key in obj) {
            this[key] = obj[key];
        }
    };
    //静态方法扩展--1.扩展核心成员
    jQuery.extend({
        isString: function (str) {
            return Object.prototype.toString.call(str) == '[object String]';
        },
        isNumber: function (num) {
            return Object.prototype.toString.call(num) == '[object Number]' && isFinite(num); //isFinite(4/0) = false
        },
        isBoolean: function (b) {
            return Object.prototype.toString.call(b) == '[object Boolean]';
        },
        isFunction: function (fn) {
            return Object.prototype.toString.call(fn) == '[object Function]';
        },
        isObject: function (obj) {
            return Object.prototype.toString.call(obj) == '[object Object]';
        },
        isDate: function (date) {
            return Object.prototype.toString.call(date) == '[object Date]';
        },
        isArray: function (arr) {
            return Object.prototype.toString.call(arr) == '[object Array]';
        },
        isReg: function (reg) {
            return Object.prototype.toString.call(reg) == '[object RegExp]';
        },
        isLikeArray: function (likeArr) {
            //1.要有length属性
            //2.要么没成员,要么一定存在key为0,1,2.....length-1(没办法判断所有的key,就只判断有没有0号和length-1号对象)
            //3.对象的__proto__不是指向Array.prototype
            return ('length' in likeArr) && (likeArr.length === 0 || (likeArr.length - 1) in likeArr && 0 in likeArr) && (likeArr.__proto__ != Array.prototype);
        },
        trim: function (str) {
            if (!str) {
                return str;
            } else {
                if (str.trim) {
                    return str.trim();
                } else {
                    return str.replace(/^\s+|\s+$/, '');
                }
            }
        },
        isHTML: function (str) { //判断字符串是不是一个HTML标签片段
            //1.首字母必须是‘<’
            //2.最后1个字母必须是'>'
            //3.<> 不行,str的长度至少是3
            if (!str) {
                return false;
            }
            if (jQuery.isString(str)) {
                if (str.charAt(0) == '<' && str.charAt(str.length - 1) == '>' && str.length >= 3) {
                    return true;
                }
            }
            return false;
        }
    });
    //静态方法扩展--2.扩展AJAX模块
    jQuery.extend({
        ajax: function (jsonData) {
            var xhr = null;
            if (window.XMLHttpRequest) {
                xhr = new XMLHttpRequest();
            } else {
                xhr = new ActiveXObject('Microsoft.XMLHTTP');
            }
            var type = jsonData.type == 'get' ? 'get' : 'post';
            var url = '';
            if (jsonData.url) {
                if (type == 'get') {
                    url += "?" + jsonData.data;
                }
            }
            var flag = jsonData.asyn = 'true' ? 'true' : 'false';
            xhr.open(type.url.flag);
            xhr.onreadystatechange = function () {
                if (this.readyState == 4 && this.status == 200) {
                    if (typeof jsonData.success == 'function') {
                        var d = jsonData.dataType = 'xml' ? xhr.responseXML : xhr.responseText;
                        jsonData.success(d);
                    }
                } else {
                    if (typeof jsonData.failure == 'function') {
                        jsonData.failure();
                    }
                }
            }
            if (type == 'get') {
                xhr.setRequestHeader("If-Modified-Since", "0");
                xhr.send(null);
            } else if (type == 'post') {
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhr.send(jsonData.data);
            }
        }
    });
    jQuery.extend({
        getStyle: function (dom, style) {
            if (window.getComputedStyle) { //判断是不是主流浏览器
                return window.getComputedStyle(dom)[style];
            } else { //如果是IE浏览器
                return dom.currentStyle[style];
            }
        }
    })


    //实例成员扩展--1.事件注册模块
    jQuery.fn.extend({
        //只实现bind
        on: function (type, fun) {
            if (jQuery.isString(type) && jQuery.isFunction(fun)) {
                //隐式迭代
                this.each(function (i, el) {
                    if (el.addEventListener) { //判断是不是主流浏览器
                        el.addEventListener(type, fun);
                    } else {
                        el.attachEvent('on' + type, fun) //ie浏览器支持的事件注册方式
                    }
                })
            }
            return this; //链式编程
        },
        click: function (fun) {
            this.on('click', fun);
        }
    });
    //实例成员扩展--2.属性操作模块
    jQuery.fn.extend({

    });
    //实例成员扩展--3.样式操作模块
    jQuery.fn.extend({
        css: function (name, val) {
            //1.只传了一个参数,读取选择器选择的第一个元素,对应的CSS属性的值
            if (arguments.length === 1) {
                if (jQuery.isString(name)) {
                    return jQuery.getStyle(this.get(0), name);
                } else if (jQuery.isObject(name)) {
                    for (var key in name) {
                        this.each(function (i, e) {
                            e.style[key] = name[key];
                        })
                    }
                }

            } else if (arguments.length === 2) { //设置样式
                this.each(function (i, e) {
                    e.style[name] = val;
                })
            }
            return this;
        }
    });
    //实例成员扩展--4.class操作模块
    jQuery.fn.extend({
        addClass: function (clsName) {
            //思路:
            //1.先判断dom对象是不是已经有该属性
            //2.如果没有,再给它添加,否则什么都不做
            this.each(function (i, e) {
                if ((' ' + this.className + ' ').indexOf(clsName = ' ' + clsName + ' ') == -1) {
                    this.className += clsName += ' ' + clsName;
                }
            });
            return this;
        },
        removeClass: function (claName) {
            //1.如果没有传递参数,就把所有选中的dom元素的class属性清空
            //2.如果传递参数了,就遍历所有dom对象,把class属性值用‘ ’替换
            if (arguments.length == 0) {
                this.each(function (i, e) {
                    e.className = ' ';
                })
            } else {
                this.each(function (i, e) {
                    this.className = jQuery.trim((' ' + this.className + ' ').replace(' ' + this.claName + ' ', ''));
                })
            }
            return this;
        }
    })
    //核心思想
    //1.隐式迭代
    jQuery.extend({
        each: function (collection, callback) {
            //1.判断callback是不是函数
            if (jQuery.isFunction(callback)) {
                //2.判断collection是不是数组或者伪数组
                if (jQuery.isArray(collection) || jQuery.isLikeArray(collection)) {
                    for (var i = 0; i < collection.length; i++) {
                        // callback(i,collection[i]);
                        //我们需要把callback调用时,其内部的this指向当前遍历到的集合的成员
                        callback.call(collection[i], i, collection[i]);
                    }
                } else {
                    for (var key in collection) {
                        callback.call(collection[key], key, collection[key]);
                    }
                }
            }
        }
    })
    //2.链式编程
    //jQuery真正的构造函数
    var init = jQuery.fn.init = function (selector) {
        //0.如果selector是string
        if (jQuery.isString(selector)) {
            //1.如果传递的selector是HTML标签片段,就创建DOM对象
            if (jQuery.isHTML(selector)) {
                //<div>文字</div>
                //标签嵌套情况:<div><p>这是段落</p></div>
                //技巧:1.先创建一个容器
                //2.然后把selecor这个字符串,整体作为容器的innerHTML添加到容器中
                //3.然后从容器中,通过找直接子元素,再找到这个DOM对象
                var tempDiv = document.createElement('div');
                tempDiv.innerHTML = selector;
                //call、apply借用
                [].push.apply(this, tempDiv.children);
            } else {
                //2.如果是选择器,那么就通过web api 去查询DOM元素
                //切割出selector的首字符
                var firstChar = selector.charAt(0);
                var lastChars = selector.substr(1);
                try {
                    //3.把创建出的DOM对象/选择器选中的DOM元素, 挂载到jQuery身上
                    if (firstChar == '#') {
                        var obj = document.getElementById(lastChars);
                        if (obj == null) {
                            return this;
                        }
                        [].push.call(this, obj);
                    } else {
                        if (firstChar == '.') {
                            var objs = document.getElementsByClassName(lastChars);
                            [].push.apply(this, objs);
                        } else {
                            var objs = document.getElementsByTagName(selector);
                            [].push.apply(this, objs);
                        }
                    }
                    return this;
                } catch {
                    this.length = 0; //4.给自己补一个length属性
                    return this;
                }


            }

        }

    }
    //把构造函数的原型,替换为jQuery工厂的原型
    //这么做的目的是为了实现插件机制,让外界可以通过jQuery方便的进行扩展
    init.prototype = jQuery.fn;

    //把jQuery工厂函数和$简写暴露出来
    win.jQuery = win.$ = jQuery;

})(window);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值