我要学习之墨鱼JQ

/**
 * moyuQuery的大部分API方法名和jQuery保持一致,可以结合jQuery的文档来阅读本库
 * www.moyu-edu.com
 * 
 */

//立即函数自执行
//把window传进来,可以不用每次访问都去全局作用域,提高代码执行速度
//因为在有的低版本IE中undefined的值有可能改写,所以传进来,但是调用的时候实参没有这个,所以保证是正确的undefined
;(function(window,undefined){
    //代码9到96行的作用在于选择出来了我们要的一组DOM对象,并存到我们的moyuQuery对象中作为一个属性名为arr的数组中
    //moyuQuery构造器
    function moyuQuery(str){
        //防止非法访问
        if(this === window){
            return new moyuQuery(str);
        }

        //Sizzle解析引擎,模拟jQuery的sizzle
        function Sizzle(str){
            var str = str.toLowerCase();
            //如果是类似$("#abc")这样的形式,直接返回,提高性能
            var quickMatchIdReg = /^#[a-z]+$/;
            if(quickMatchIdReg.test(str)){
                return [document.getElementById(str)];
            }

            var list = str.split(" ");
            var eleArr = [];
            var tempArr = [];

            for(var i=0;i<list.length;i++){
                if(eleArr.length === 0){
                    eleArr = manipuEasyDom(list[i],document);
                }else{
                    tempArr = [];//每次进来执行的时候置空tempArr
                    for(var j=0;j<eleArr.length;j++){
                        tempArr = tempArr.concat(manipuEasyDom(list[i],eleArr[j]));
                    }
                    eleArr = tempArr;
                }
                
            }
            // 只考虑了最简单的三种情况选择器 id,class,标签
            function manipuEasyDom(str,fatherDom){
                var reg1 = /^#(w+)/;//匹配id
                var reg2 = /^.(w+)/;//匹配class
                var reg3 = /^w+/;//匹配标签

                var myArr = [];
                //str代表的是传进来的参数 "#abc" ".abc" "abc"
                if(reg1.test(str) === true){
                    var arr = reg1.exec(str);
                    //console.log(arr);
                    var oDiv = fatherDom.getElementById(arr[1]);
                    myArr.push(oDiv);
                }

                if(reg2.test(str) === true){
                    var arr = reg2.exec(str);
                    var aList = fatherDom.getElementsByClassName(arr[1]);
                    myArr = Array.prototype.slice.call(aList,0);
                }

                if(reg3.test(str) === true){
                    var aList = fatherDom.getElementsByTagName(str);
                    myArr = Array.prototype.slice.call(aList,0);
                }
                return myArr;
            }
            return eleArr;
        }

        //判断是 $(function(){})、$("#demo") 还是其他的调用类型
        switch(typeof str){
            case "function"://如果是$(function(){})这种方式,那就是简写的ready形式    
                moyuQuery.ready(str);
                break;
            case "string"://只考虑像 $("#a div") $(".a div") $("div .item") $("div") $(".item") $("#a")这些形式,不考虑伪类、CSS3选择器
                this.arr = Sizzle(str);
                break;
            case "object":
                //说明是用getElementsByTagName,getElementsByClassName选择出来的
                if(str.toString().indexOf("Element") > -1){
                    this.arr = [str];

                //说明是用getElementsByTagName,getElementsByClassName选择出来的    
                }else if(str.toString().indexOf("Collection") > -1){
                    this.arr = str;
                //出错了    
                }else{
                    return {};
                }
                break;
            default:
                //出错了    
                return {};
                break;    
        }
    }



    //eq就是等于的意思
    //eq(0) --> 把arr数组的第1个拿出来
    moyuQuery.prototype.eq = function(num){
        return new moyuQuery(this.arr[num]);
    }

    //获取第一个元素DOM对象并转换成moyuQuery对象
    moyuQuery.prototype.first = function(){
        return new moyuQuery(this.arr[0]);
    }

    //获取最后一个元素DOM对象并转换成moyuQuery对象
    moyuQuery.prototype.last = function(){
        return new moyuQuery(this.arr[this.arr.length - 1]);
    }



    //求整个moyuQuery对象中的DOM元素的个数
    moyuQuery.prototype.length = function(){
        return this.arr.length;
    }
    //求整个moyuQuery对象中的DOM元素的个数
    moyuQuery.prototype.size = moyuQuery.prototype.length;


    //+++++++++++++++++++++++++++++事件模块开始+++++++++++++++++++++++++++++++++++++++++++
    //on相当于给this.arr里所有的元素对象加事件
    moyuQuery.prototype.on = function(eventType,fn){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].addEventListener(eventType,fn,false);
        }
        return this;
    }

    //给一些常见的事情设置一些快捷方式,比如click可以直接 $("div").click(function(){})这样用
    var eventList = 'click mouseover mouseout mousedown mousemove mouseup keydown keyup dblclick contextmenu input propertychange change blur focus resize scroll load'.split(" ");
    for(var i=0;i<eventList.length;i++){
        //这里用到了闭包的技巧
        moyuQuery.prototype[eventList[i]] = (function(eventType){
            var eventFn = function(fn){
                this.on(eventType,fn);
            }
            return eventFn;
        })(eventList[i]);
    }    

    //ele.removeEventListener("click",fnName);
    //off相当于给this.arr里面所有的元素对象移除事件
    moyuQuery.prototype.off = function(eventType,fn){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].removeEventListener(eventType,fn);
        }
        return this;
    }

    //类似css中的hover伪类
    moyuQuery.prototype.hover = function(fn1,fn2){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].addEventListener("mouseenter",fn1,false);
            this.arr[i].addEventListener("mouseleave",fn2,false);
        }
    }

    //++++++++++++++++++++++++++++++++事件模块结束++++++++++++++++++++++++++++++++++++++++


    //++++++++++++++++++++++++++++++++DOM模块开始++++++++++++++++++++++++++++++++++++++++
    //show给this.arr里所有的元素让它显示出来
    moyuQuery.prototype.show = function(){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].style.display = "block";
        }
        return this;
    }

    //hide给this.arr里所有的元素让它隐藏出来
    moyuQuery.prototype.hide = function(){
        console.log(this.arr);
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].style.display = "none";
        }
        return this;
    }

    //如果显示,就隐藏,否则显示
    moyuQuery.prototype.toggle = function(){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].addEventListener("click",function(){
                if(getStyle(this).display === "block"){
                    this.style.display = "none";
                }else{
                    this.style.display = "block";
                }
            },false);
        }
    }

    //获取计算后样式
    function getStyle(ele){
        if(window.getComputedStyle){
            return getComputedStyle(ele);
        }else{
            return ele.currentStyle;
        }
    }

    //如果传进来一个参数是获取,否则是设置
    moyuQuery.prototype.css = function(styleName,styleValue){
        if(styleValue === undefined){
            return getStyle(this.arr[0])[styleName];
        }else{
            for(var i=0;i<this.arr.length;i++){
                this.arr[i].style[styleName] = styleValue;
            }
        }        
    }

    //如果传进来一个参数是获取,否则是设置
    moyuQuery.prototype.attr = function(attrName,attrValue){
        if(attrValue === undefined){
            return this.arr[0].getAttribute(attrName);
        }else{
            for(var i=0;i<this.arr.length;i++){
                this.arr[i].setAttribute(attrName,attrValue);
            }
        }
    }

    //如果传进来一个参数是获取,否则是设置
    moyuQuery.prototype.val = function(valName,valValue){
        if(valName === undefined){
            return this.arr[0][valName];
        }else{
            for(var i=0;i<this.arr.length;i++){
                this.arr[i][valName] = valValue;
            }
        }
    }


    // 给this.arr里所有的元素加一个className "abc def"
    moyuQuery.prototype.addClass = function(str){
        for(var i=0;i<this.arr.length;i++){
            //"abc" "abc def"
            this.arr[i].className += " " + str;
        }
    }

    //移出类名
    moyuQuery.prototype.removeClass = function(str){
        for(var i=0;i<this.arr.length;i++){
            //"abc def abc"
            var reg = new RegExp("\b" + str + "\b","g");
            this.arr[i].className = this.arr[i].className.replace(reg,"");
            // this.arr[i].className += " " + str;
        }
    }

    //如果存在(不存在)就删除(添加)一个类。
    //原型 
    moyuQuery.prototype.toggleClass = function(str){
        for(var i=0;i<this.arr.length;i++){
            var reg = new RegExp("\b" + str + "\b","g");
            "abc def"
            if(reg.test(this.arr[i].className) === true){
                this.arr[i].className = this.arr[i].className.replace(reg,"");
            }else{
                this.arr[i].className += " " + str;
            }
        }
    }
    // myObj.html("abc");
    moyuQuery.prototype.html = function(str){
        if(str === undefined){
            return this.arr[0].innerHTML;
        }
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].innerHTML = str;
        }
    }

    //参考innerText的功能
    moyuQuery.prototype.text = function(str){
        if(str === undefined){
            return this.arr[0].innerText;
        }
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].innerHTML = str;
        }
    }

    //清空moyuQuery中的DOM对象的innerHTML
    moyuQuery.prototype.empty = function(){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].innerHTML = "";
        }
    }

    //删除moyuQuery中的DOM对象
    moyuQuery.prototype.remove = function(){
        for(var i=0;i<this.arr.length;i++){
            this.arr[i].parentNode.removeChild(this.arr[i]);
        }
    }

    //获取和设置
    moyuQuery.prototype.width = function(widthValue){
        if(widthValue === undefined){
            return getStyle(this.arr[0]).width;
        }else{
            for(var i=0;i<this.arr.length;i++){
                this.arr[i].style.width = widthValue + "px";
            }
        }
    }

    //获取和设置
    moyuQuery.prototype.height = function(heightValue){
        if(heightValue === undefined){
            return getStyle(this.arr[0]).height;
        }else{
            for(var i=0;i<this.arr.length;i++){
                this.arr[i].style.height = heightValue + "px";
            }
        }
    }

    moyuQuery.prototype.innerWidth = function(){
        var styleObj = getStyle(this.arr[0]);
        return parseInt(styleObj["width"]) + parseInt(styleObj["paddingLeft"]) + parseInt(styleObj["paddingRight"]);
    }

    moyuQuery.prototype.innerHeight = function(){
        var styleObj = getStyle(this.arr[0]);
        return parseInt(styleObj["height"]) + parseInt(styleObj["paddingTop"]) + parseInt(styleObj["paddingBottom"]);
    }

    moyuQuery.prototype.outerWidth = function(check){
        var styleObj = getStyle(this.arr[0]);
        if(check === true){
            return parseInt(styleObj["width"]) + parseInt(styleObj["paddingLeft"]) + parseInt(styleObj["paddingRight"]) + parseInt(styleObj["borderLeftWidth"]) + parseInt(styleObj["borderRightWidth"]) + parseInt(styleObj["marginLeft"]) + parseInt(styleObj["marginRight"]);
        }else{
            return parseInt(styleObj["width"]) + parseInt(styleObj["paddingLeft"]) + parseInt(styleObj["paddingRight"]) + parseInt(styleObj["borderLeftWidth"]) + parseInt(styleObj["borderRightWidth"]);
        }
    }

    moyuQuery.prototype.outerHeight = function(){
        var styleObj = getStyle(this.arr[0]);
        if(check === true){
            return parseInt(styleObj["height"]) + parseInt(styleObj["paddingTop"]) + parseInt(styleObj["paddingBottom"]) + parseInt(styleObj["borderTopWidth"]) + parseInt(styleObj["borderBottomWidth"]) + parseInt(styleObj["marginTop"]) + parseInt(styleObj["marginBottom"]);
        }else{
            return parseInt(styleObj["height"]) + parseInt(styleObj["paddingTop"]) + parseInt(styleObj["paddingBottom"]) + parseInt(styleObj["borderTopWidth"]) + parseInt(styleObj["borderBottomWidth"]);
        }
    }

    //获取当前元素与CSS定位上的父级的偏移量    
    moyuQuery.prototype.offset = function(){
        return {
            left:this.arr[0].offsetLeft,
            top:this.arr[0].offsetTop
        };
    }


    function getPos(ele){
        var posObj = {
            left:ele.offsetLeft + parent.clientLeft - parent.scrollLeft,
            top:ele.offsetTop + parent.clientTop- parent.scrollTop
        }
        var parent = ele.offsetParent;
        while(parent!=null){
            posObj.left += parent.offsetLeft + parent.clientLeft - parent.scrollLeft;
            posObj.top += parent.offsetTop + parent.clientTop- parent.scrollTop;
            parent = parent.offsetParent;
        }
        return posObj;
    }

    // 把moyuQuery中的DOM对象包一层父级
    moyuQuery.prototype.position = function(){
        return getPos(this.arr[0]);
    }

    moyuQuery.prototype.scrollLeft = function(){
        return this.arr[0].scrollLeft;
    }

    moyuQuery.prototype.scrollTop = function(){
        return this.arr[0].scrollTop;
    }

    //获取第1个DOM对象与视窗的偏移坐标
    moyuQuery.wrap = function(str){
        var fragment = document.createDocumentFragment();
        var oDiv = document.createElement("div");
        fragment.appendChild(oDiv);
        oDiv.innerHTML = str;
        var myEle = oDiv.children[0];
        for(var i=0;i<this.arr.length;i++){
            var myEle1 = myEle.cloneNode(true);
            this.arr[i].parentNode.insertBefore(myEle1,this.arr[i]);
            myEle1.appendChild(this.arr[i]);
        }
    }

    //把当前的DOM对象这一层去掉
    moyuQuery.prototype.unwrap = function(){
        for(var i=0;i<this.arr.length;i++){
            //找出来所有的当前DOM对象的子元素,先加到对应的位置,再把当前DOM对象删除掉
            var myChildren = this.arr[i].children;
            for(var j=0;j<myChildren.length;j++){
                this.arr[i].parentNode.insertBefore(this.arr[i].children,this.arr[i]);
            }
            this.arr[i].parentNode.removeChild(this.arr[i]);
        }
    }
    //++++++++++++++++++++++++++++++++DOM模块结束++++++++++++++++++++++++++++++++++++++++


    //++++++++++++++++++++++++++++++++ajax&jsonp模块开始++++++++++++++++++++++++++++++++++++++++

    //jsonp方式获取数据
    moyuQuery.jsonp = function(link,fn){
        window.fn = fn;
        var oScript = document.createElement("script");
        oScript.src = link;
    }


    //args代表的是传的参数
    moyuQuery.get = function(link,args,fn){
        var xhr = null;
        if(window.XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }

        xhr.open("GET",link+"?a="+(new Date()).getTime()+"&"+args);
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.status === 200){
                if(typeof fn === "function"){
                    fn();
                }
            }
        }
        xhr.send(null);
    }

    //ajax的POST方式提交数据
    moyuQuery.post = function(){
        var xhr = null;
        if(window.XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }

        xhr.open("POST",link);
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.status === 200){
                if(typeof fn === "function"){
                    fn();
                }
            }
        }
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        xhr.send(args);
    }
    //++++++++++++++++++++++++++++++++ajax&jsonp模块结束++++++++++++++++++++++++++++++++++++++++


    //缓存数据
    moyuQuery.prototype.data = function(valName,valValue){
        if(valValue === undefined){
            return this[valName];
        }else{
            this[valName] = valValue;
        }
    }

    //表单序列化
    moyuQuery.prototype.serialize = function(){
        var list = this.arr[0].getElementsByTagName('*');
        var tempStr = "";
        for(var i=0;i<list.length;i++){
            if(list[i].tagName.toLowerCase() === "input"){
                if(list[i].getAttribute("type").search(/text|password|email|date|range|color|url/)){
                    tempStr += list[i].getAttribute("name") + "=" + list[i].value + "&";
                }
            }
        }
        return tempStr.replace(/&$/,"");
    }

    //裁剪
    moyuQuery.prototype.slice = function(m,n){
        this.arr.slice(m,n);
        return this;
    }
    //插件化
    moyuQuery.prototype.extend = function(obj){
        for(var i in obj){
            this[i] = obj[i];
        }
    }

    //each
    //fn默认形参 index ele
    moyuQuery.prototype.each = function(fn){
        for(var i=0;i<this.arr.length;i++){
            fn.call(window,i,this.arr[i]);
        }
    }




    //当DOM载入就绪可以查询及操纵时绑定一个要执行的函数。
    moyuQuery.ready = function(fn){
        if(document.addEventListener){
            document.addEventListener("DOMContentLoaded",function(){
                if(typeof fn === "function"){
                    fn();
                }
            },false);
        }else{
            document.onreadystatechange = function(evt){
                evt = evt || event;
                if(evt.readyState === "complete"){
                    if(typeof fn === "functioin"){
                        fn();
                    }
                }
            }
        }
    }

    moyuQuery.each = function(arr,fn){
        for(var i=0;i<arr.length;i++){
            fn(i,arr[i]);
        }
    }

    //exObj对象的属性拷贝到srcObj身上
    moyuQuery.extend = function(srcObj,exObj){
        for(var i in exObj){
            srcObj[i] = exObj[i];
        }
    }

    //检测该字符串是否像数字
    moyuQuery.isNumeric = function(str){
        if(typeof str === "number"){
            return true;
        }
        var reg = /^d+$/;
        if(reg.test(str)){
            return true;
        }else{
            return false;
        }
    }

    //检测是否是数组类型数据
    moyuQuery.isArray = function(arr){
        if(Object.prototype.toString.call(arr).indexOf("Array") > -1){
            return true;
        }else{
            return false;
        }
    }

    moyuQuery.isPlainObject = function(obj){
        if(Object.prototype.toString.call(obj) === "[object Object]"){
            return true;
        }else{
            return false;
        }
    }

    moyuQuery.type = function(ele){
        switch(Object.prototype.toString.call(ele)){
            case "[object Array]":
                return "array";
                break;
            case "[object Date]":
                return "date";
                break;
            case "[object RegExp]":
                return "regexp";
                break;
            case "[object String]":
                return "string";
                break;
            case "[object Function]":
                return "function";
                break;
            case "[object Number]":
                return "number";
                break;
            case "[object Boolean]":
                return "boolean";
                break;
            case "[object Null]":
                return "null";
            case "[object Undefined]":
                return "undefined";
                break;
        }
    }

    moyuQuery.merge = function(arr1,arr2){
        return arr1.concat(arr2);
    }

    //保证数组中没有元素相同,去重
    moyuQuery.unique = function(arr1){
        var arr = [];
        for(var i=0;i<arr1.length;i++){
            if(arr.indexOf(arr1[i]) === -1){
                arr.push(arr[i]);
            }
        }
        return arr;
    }

    moyuQuery.makeArray = function(list){
        return Object.prototype.slice.call(list);
    }

    moyuQuery.inArray = function(item,arr){
        if(arr.indexOf(item) > -1){
            return true;
        }else{
            return false;
        }
    }

    //过滤函数
    moyuQuery.grep = function(arr,fn){
        var myArr = [];
        for(var i=0;i<arr.length;i++){
            if(fn(arr[i]) === true){
                myArr.push(arr[i]);
            }
        }
        return myArr;
    }

    moyuQuery.noop = function(){}

    moyuQuery.trim = function(str){
        var reg = /^s+|s+$/g;
        return str.replace(reg,"");
    }


    moyuQuery.map = function(arr,fn){
        var newArr = [];
        for(var i=0;i<arr.length;i++){
            newArr.push(fn(arr[i]));
        }
        return newArr;
    }

    //把"background-color"转换成"backgroundColor"
    moyuQuery.camelCase = function(str){
        var reg = /-(w)/g;
        return str.replace(reg,function(a,b){
            return b.toUpperCase();
        });
    }

    //检查元素的
    moyuQuery.now = function(){
        return (new Date());
    }

    //防冲突
    moyuQuery._$ = window.$;
    moyuQuery.noConflict = function(){
        window.$ = moyuQuery._$;
    }

    moyuQuery.VERSION = "0.01";

    //var a = 1;
    //window.a = a;
    
    
    //暴露给全局只有moyuQuery和$对象
    window.moyuQuery  = moyuQuery;//设置了一个全局变量名字叫$,值是moyuQuery
    window.$ = moyuQuery
    
}(window));
原文地址:https://www.cnblogs.com/shanchenba/p/5567408.html