jQuery原理(自己封裝一個(gè)jQuery)

jQuery原理

1.來(lái)看一下jQuery自己的結(jié)構(gòu)

  • (function( window, undefined ) {
         var jQuery = function( ) {
             return new jQuery.prototype.init( );
         }
         jQuery.prototype = {
             constructor: jQuery,
              init:function(){}
         }
         jQuery.prototype.init.prototype = jQuery.prototype;
         window.jQuery = window.$ = jQuery;
     })( window );
    /*
    1.jQuery的本質(zhì)是一個(gè)閉包
    2.jQuery為什么要使用閉包來(lái)實(shí)現(xiàn)?
      為了避免多個(gè)框架的沖突
    3.jQuery如何讓外界訪問(wèn)內(nèi)部定義的局部變量
       window.xxx = xxx;
    4.jQuery為什么要給自己傳遞一個(gè)window參數(shù)?
       為了方便后期壓縮代碼,直接將window賦值給一個(gè)短的變量
       為了提升查找的效率
    5.jQuery為什么要給自己接收一個(gè)undefined參數(shù)?
       為了方便后期壓縮代碼
       IE9以下的瀏覽器undefined可以被修改, 為了保證內(nèi)部使用的undefined不被修改, 所以需要接收            一個(gè)正確的undefined
     6.new jQuery.prototype.init( );
        為了在init里訪問(wèn)jQuery里邊的方法,將init的原型改為jQuery的原型
    */
    

以上搭建框架的原型圖![8D`9TUHYG(N)BB98TDIGQI.png

我們也仿照這個(gè)格式來(lái)搭建自己的基本結(jié)構(gòu)

  • (function( window, undefined ) {
         var njQuery = function( ) {
             return new njQuery.prototype.init( );
         }
         njQuery.prototype = {
             constructor: njQuery
         }
         njQuery.prototype.init.prototype = njQuery.prototype;
         window.njQuery = window.$ = njQuery;
     })( window );
    

2.入口函數(shù)

2.1入口函數(shù)測(cè)試
  • <script>
        window.onload = function (ev) {
        // $(function () {
            /*
            jQ入口函數(shù)傳入不同參數(shù)得到的實(shí)例
            1.傳入 '' null undefined NaN  0  false
            2.傳入html片段
            3.傳入選擇器
            4.傳入數(shù)組
            5.傳入偽數(shù)組
            6.傳入對(duì)象
            7.傳入DOM元素
            8.傳入基本數(shù)據(jù)類型
             */
            //  1.傳入 '' null undefined NaN  0  false
            // 會(huì)返回一個(gè)空的jQuery對(duì)象給我們
            console.log($());
            console.log($(''));
            console.log($(null));
            console.log($(undefined));
            console.log($(NaN));
            console.log($(0));
            console.log($(false));
    
            // 2.傳入html片段
            // 會(huì)將創(chuàng)建好的DOM元素存儲(chǔ)到j(luò)Query對(duì)象中返回
            console.log($('<p>1</p><p>2</p><p>3</p>'));
            // console.log($('    <div><p>1</p></div><div><p>2</p></div>    '));
    
            // 3.傳入選擇器
            // 會(huì)將找到的所有元素存儲(chǔ)到j(luò)Query對(duì)象中返回
            console.log($('li'));
    
            // 4.傳入數(shù)組
            // 會(huì)將數(shù)組中存儲(chǔ)的元素依次存儲(chǔ)到j(luò)Query對(duì)象中立返回
            var arr = [1, 2, 3, 4, 5, 6];
            console.log($(arr));
    
            // 5.傳入偽數(shù)組
            // 會(huì)將數(shù)組中存儲(chǔ)的元素依次存儲(chǔ)到j(luò)Query對(duì)象中立返回
            var likeArr = {0:"lnj", 1:"33", 2:"male", length: 3};
            console.log($(likeArr));
    
            // console.log(typeof arr);
            // console.log(typeof likeArr);
            // console.log(arr.toString());
            // console.log(likeArr.toString());
            // console.log(({}).toString.apply(arr));
    
            // 6.傳入對(duì)象
            // 會(huì)將傳入的對(duì)象存儲(chǔ)到j(luò)Query對(duì)象中返回
            function Person() {}
            console.log($(new Person()));
    
            // 7.傳入DOM元素
            // 會(huì)將傳入的DOM元素存儲(chǔ)到j(luò)Query對(duì)象中返回
            console.log($(document.createElement('div')));
    
            // 8.傳入基本數(shù)據(jù)類型
            // 會(huì)將傳入的基本數(shù)據(jù)類型存儲(chǔ)到j(luò)Query對(duì)象中返回
            console.log($(123));
            console.log($(true));
    
            /*
             1.傳入 '' null undefined NaN  0  false, 返回空的jQuery對(duì)象
             2.字符串:
             代碼片段:會(huì)將創(chuàng)建好的DOM元素存儲(chǔ)到j(luò)Query對(duì)象中返回
             選擇器: 會(huì)將找到的所有元素存儲(chǔ)到j(luò)Query對(duì)象中返回
             3.數(shù)組:
             會(huì)將數(shù)組中存儲(chǔ)的元素依次存儲(chǔ)到j(luò)Query對(duì)象中立返回
             4.除上述類型以外的:6 7 8
             會(huì)將傳入的數(shù)據(jù)存儲(chǔ)到j(luò)Query對(duì)象中返回
            */
            // });
        }
    </script>
    

先來(lái)了解一些方法

2.2 call和apply
  • <script>
        /*
        apply和call方法的作用:
        專門用于修改方法內(nèi)部的this
    
        格式:
        call(對(duì)象, 參數(shù)1, 參數(shù)2, ...);
        apply(對(duì)象, [數(shù)組]);
        */
        function test() {
            console.log(this);
        }
        // window.test();
        var obj = {"name": "lnj2"};
        /*
        1.通過(guò)window.test找到test方法
        2.通過(guò)apply(obj)將找到的test方法內(nèi)部的this修改為自定義的對(duì)象
        */
         window.test.apply(obj);
         window.test.call(obj);
    
        function sum(a, b) {
            console.log(this);
            console.log(a + b);
        }
        // window.sum.call(obj, 1, 2);
        /*
        1.通過(guò)window.sum找到sum方法
        2.通過(guò)apply(obj)將找到的sum方法內(nèi)部的this修改為自定義的對(duì)象
        3.將傳入數(shù)組中的元素依次取出, 傳遞給形參
        */
         window.sum.apply(obj, [3, 5]);
    
    
        // 真數(shù)組轉(zhuǎn)換偽數(shù)組的一個(gè)過(guò)程
        // var arr = [1, 3, 5, 7, 9];
        // var obj = {};
        /*
        1.通過(guò)[].push找到數(shù)組中的push方法
        2.通過(guò)apply(obj)將找到的push方法內(nèi)部的this修改為自定義的對(duì)象
        3.將傳入數(shù)組中的元素依次取出, 傳遞給形參
        */
        [].push.apply(obj, arr);
        console.log(obj);
        window.onload = function (ev) {
            // 系統(tǒng)自帶的偽數(shù)組
            var res = document.querySelectorAll("div");
            // 自定義的偽數(shù)組
            var obj = {0:"lnj", 1:"33", length: 2};
            // var arr = []; // 真數(shù)組
            // [].push.apply(arr, obj);
            // console.log(arr);
    
            //上面這個(gè)方法只能在IE9以上的瀏覽器用,所以使用 如果想將偽數(shù)組轉(zhuǎn)換為真數(shù)組那么可以使用如下方法
            var arr = [].slice.call(obj);
            //即將數(shù)組的this改為obj,然后通過(guò)slice方法什么參數(shù)都沒(méi)有傳遞,將數(shù)組中的元素放到一個(gè)新的數(shù)組中原樣返回
            console.log(arr);
            // var arr2 = [1, 3, 5, 7, 9];
            // 如果slice方法什么參數(shù)都沒(méi)有傳遞, 會(huì)將數(shù)組中的元素放到一個(gè)新的數(shù)組中原樣返回
            // var res2 = arr2.slice();
            // var res2 = arr2.slice(2);
            // var res2 = arr2.slice(2, 4);
            // console.log(res2);
        }
    </script>
    
2.3 去除傳入字符串兩邊的空格
  • function(str){
        if(!njQuery.isString(str)){
            return str;
        }
        // 判斷是否支持trim方法 高版本瀏覽器
        if(str.trim){
            return str.trim();
        }else{
            return str.replace(/^\s+|\s+$/g, "");//正則表達(dá)式
        }
    }
    
2.4 判斷是不是數(shù)組
  • //是數(shù)組的話一定是對(duì)象,并且具有l(wèi)ength屬性,并且不是window
    function(sele){
        if(njQuery.isObject(sele) &&
            !njQuery.isWindow(sele) &&
            "length" in sele){
            return true;
        }
        return false;
    }
    
2.5 extend方法
  • //當(dāng)我們有很多自定義的函數(shù)時(shí),在維護(hù)時(shí)會(huì)很不方便,extend就是為了解決這個(gè)問(wèn)題
    function njQuery() {
    
    }
    /*
    njQuery.extend = function (obj) {
        // 此時(shí)此刻的this就是njQuery這個(gè)類
        // console.log(this);
        for(var key in obj){
            // njQuery["isTest"] = function () {console.log("test");}
            this[key] = obj[key];
        }
    }
    njQuery.extend({
        isTest: function () {
            console.log("test");
        }
    });
    njQuery.isTest();
    */
    /*
    njQuery.prototype.extend = function (obj) {
        // 此時(shí)此刻的this是njQuery對(duì)象
        // console.log(this);
        for(var key in obj){
            // q["isDemo"] = function () {console.log("demo");}
            this[key] = obj[key];
        }
    }
    var q = new njQuery();
    q.extend({
        isDemo: function () {
            console.log("demo");
        }
    });
    q.isDemo();
    */
    //將以上兩種合起來(lái)寫就是下面這樣的,既可以添加靜態(tài)方法,又可以添加實(shí)例方法
    njQuery.extend = njQuery.prototype.extend = function (obj) {
        //console.log(this);
        for(var key in obj){
            this[key] = obj[key];
        }
    }
     njQuery.extend({});
    var q = new njQuery();
    q.extend();
    
2.6判斷dom元素是否加載完畢
  • /*
    onload事件會(huì)等到DOM元素加載完畢, 并且還會(huì)等到資源也加載完畢才會(huì)執(zhí)行
    DOMContentLoaded事件只會(huì)等到DOM元素加載完畢就會(huì)執(zhí)行回調(diào)
    */
    /*
    window.onload = function (ev) {
        // var res = document.querySelectorAll("div");
        // console.log(res);
        console.log("onload");
    }
    document.addEventListener("DOMContentLoaded", function () {
        // var res = document.querySelectorAll("div");
        // console.log(res);
        console.log("DOMContentLoaded");
    });
    但是低版本的瀏覽器不支持addEventListene
    */
    /*
    document.readyState屬性有如下的狀態(tài)
    uninitialized - 還未開(kāi)始載入
    loading - 載入中
    interactive - 已加載,文檔與用戶可以開(kāi)始交互
    complete - 載入完成
    
    onreadystatechange事件就是專門用于監(jiān)聽(tīng)document.readyState屬性的改變的
    */
    /*
    以下是在低版本瀏覽器中也能用
    document.attachEvent("onreadystatechange", function () {
        if(document.readyState == "complete"){
            console.log("onreadystatechange");
        }
    });
    */
    //綜上所述,用來(lái)判斷的方法就是
    if(document.addEventListener){
        document.addEventListener("DOMContentLoaded", function () {
            fn();
        });
    }else{
        document.attachEvent("onreadystatechange", function () {
            if(document.readyState == "complete"){
               fn();
            }
        });
    }
    
    $(function () {
        var res = document.querySelectorAll("div");
        console.log(res);
    });
    

實(shí)現(xiàn)以下方法

//jQ原型上的核心方法和屬性:
/*
        
             1、jquery 獲取jQ版本號(hào)
             2、selector 實(shí)例默認(rèn)的選擇器取值
             3、length 實(shí)例默認(rèn)的長(zhǎng)度
             3、push 給實(shí)例添加新元素
             4、sort 對(duì)實(shí)例中的元素進(jìn)行排序
             5、splice 按照指定下標(biāo)指定數(shù)量刪除元素,也可以替換刪除的元素

             6、toArray 把實(shí)例轉(zhuǎn)換為數(shù)組返回
             7、get  獲取指定下標(biāo)的元素,獲取的是原生DOM

             6、eq 獲取指定下標(biāo)的元素,獲取的是jQuery類型的實(shí)例對(duì)象
             7、first 獲取實(shí)例中的第一個(gè)元素,是jQuery類型的實(shí)例對(duì)象
             8、last 獲取實(shí)例中的最后一個(gè)元素,是jQuery類型的實(shí)例對(duì)象

             9、each 遍歷實(shí)例,把遍歷到的數(shù)據(jù)傳給回調(diào)使用
             10、map  遍歷實(shí)例,把遍歷到的數(shù)據(jù)傳給回調(diào)使用,然后把回調(diào)的返回值收集起來(lái)組成一個(gè)新的數(shù)組返回
          */
//dom操作相關(guān)的方法
/*
             1、empty ==> 清空指定元素中的所有內(nèi)容
             2、remove ==> 刪除所有的元素或指定元素
             3、html ==> 設(shè)置所有元素的內(nèi)容,獲取第一個(gè)元素的內(nèi)容
             4、text ==> 設(shè)置所有元素的文本內(nèi)容,獲取所有元素的文本內(nèi)容
            5、元素.appendTo.指定元素 ==> 將元素添加到指定元素內(nèi)部的最后
            6.元素.prependTo.指定元素 ==> 將元素添加到指定元素內(nèi)部的最前面
            7、指定元素.append.元素 ==> 將元素添加到指定元素內(nèi)部的最后
            8、指定元素.prepend.元素 ==> 將元素添加到指定元素內(nèi)部的最前面
            9.元素.insertBefore.指定元素  ==>將元素添加到指定元素外部的前面
            10.next([expr]) 獲取緊鄰的后面同輩元素的元素
             11.prev([expr]) 獲取元素緊鄰的前一個(gè)同輩元素             
             12.元素.insertAfter.指定元素  ==>將元素添加到指定元素外部的后面
             13.指定元素.after.元素  ==>將元素添加到指定元素外部的后面
             14.元素.insertBefore.指定元素  ==>將元素添加到指定元素外部的前面
             15.指定元素.before.元素  ==>將元素添加到指定元素外部的前面
             16、元素.replaceAll.指定元素 ==> 替換所有指定元素
             17.指定元素.replaceWith.元素 ==> 替換所有指定元素
*/
//屬性操作相關(guān)方法
/*
            1.attr(): 設(shè)置或者獲取元素的屬性節(jié)點(diǎn)值
            2.prop(): 設(shè)置或者獲取元素的屬性值
            3.css(): 設(shè)置獲取樣式
            4.val(): 獲取設(shè)置value的值
            5.hasClass(): 判斷元素中是否包含指定類
            6.addClass(): 給元素添加一個(gè)或多個(gè)指定的類
            7.removeClass(): 刪除元素中一個(gè)或多個(gè)指定的類
            8.toggleClass(): 沒(méi)有則添加,有則刪除
*/
//事件操作相關(guān)方法
/*
          1.on(type, callback): 注冊(cè)事件
          2.off(type, callback): 移出事件
*/

代碼實(shí)現(xiàn)

(function( window, undefined ) {
    var njQuery = function(selector) {
        return new njQuery.prototype.init(selector);
    }
    njQuery.prototype = {
        constructor: njQuery,
        init: function (selector) {
            // 0.去除字符串兩端的空格
            selector = njQuery.trim(selector);
            // 1.傳入 '' null undefined NaN  0  false, 返回空的jQuery對(duì)象
            if(!selector){
                return this;
            }
            // 2.方法處理
            else if(njQuery.isFunction(selector)){
                njQuery.ready(selector);
            }
            // 3.字符串
            else if(njQuery.isString(selector)){
                // 2.1判斷是否是代碼片段 <a>
                if(njQuery.isHTML(selector)){
                    // 1.根據(jù)代碼片段創(chuàng)建所有的元素
                    var temp = document.createElement("div");
                    temp.innerHTML = selector;
                    // 2.將創(chuàng)建好的一級(jí)元素添加到j(luò)Query當(dāng)中
                    [].push.apply(this, temp.children);
                }
                // 2.2判斷是否是選擇器
                else{
                    // 1.根據(jù)傳入的選擇器找到對(duì)應(yīng)的元素
                    var res = document.querySelectorAll(selector);
                    // 2.將找到的元素添加到njQuery上
                    [].push.apply(this, res);
                }
            }
            // 4.數(shù)組
            else if(njQuery.isArray(selector)){
                // 轉(zhuǎn)換為真數(shù)組
                var arr = [].slice.call(selector);
                // 將真數(shù)組數(shù)據(jù)添加到njQuery上
                [].push.apply(this, arr);
            }
            // 5.除上述類型以外
            else{
                this[0] = selector;
                this.length = 1;
            }
            // 返回njQuery
            return this;
        },
        jquery: "1.1.0",
        selector: "",
        length: 0,
        push: [].push,
        sort: [].sort,
        splice: [].splice,
        toArray: function () {
            return [].slice.call(this);
        },
        get: function (num) {
            // 沒(méi)有傳遞參數(shù)
            if(arguments.length === 0){
                return this.toArray();
            }
            // 傳遞不是負(fù)數(shù)
            else if(num >= 0){
                return this[num];
            }
            // 傳遞負(fù)數(shù)
            else{
                return this[this.length + num];
            }
        },
        eq: function (num) {
            // 沒(méi)有傳遞參數(shù)
            if(arguments.length === 0){
                return new njQuery();
            }else{
                return njQuery(this.get(num));
            }
        },
        first: function () {
            return this.eq(0);
        },
        last: function () {
            return this.eq(-1);
        },
        each: function (fn) {
            return njQuery.each(this, fn);
        }
    }
    njQuery.extend = njQuery.prototype.extend = function (obj) {
        for(var key in obj){
            this[key] = obj[key];
        }
    }
    // 工具方法
    njQuery.extend({
        isString : function(str){
            return typeof str === "string"
        },
        isHTML : function(str){
            return str.charAt(0) === "<" &&
                str.charAt(str.length - 1) === ">" &&
                str.length >= 3;
        },
        trim : function(str){
            if(!njQuery.isString(str)){
                return str;
            }
            // 判斷是否支持trim方法
            if(str.trim){
                return str.trim();
            }else{
                return str.replace(/^\s+|\s+$/g, "");
            }
        },
        isObject : function(sele){
            return typeof sele === "object"
        },
        isWindow : function(sele){
            return sele === window;
        },
        isArray : function(sele){
            if(njQuery.isObject(sele) &&
                !njQuery.isWindow(sele) &&
                "length" in sele){
                return true;
            }
            return false;
        },
        isFunction : function(sele){
            return typeof sele === "function";
        },
        ready: function (fn) {
            // 如果已經(jīng)加載過(guò)了, 那么直接調(diào)用回調(diào)
            if(document.readyState == "complete"){
                fn();
            }
            // 如果沒(méi)有加載過(guò),判斷是否支持addEventListener方法, 支持就使用addEventListener方法監(jiān)聽(tīng)DOM加載
            else if(document.addEventListener){
                document.addEventListener("DOMContentLoaded", function () {
                    fn();
                });
            }
            // 如果不支持addEventListener方法, 就使用attachEvent方法監(jiān)聽(tīng)
            else{
                document.attachEvent("onreadystatechange", function () {
                    if(document.readyState == "complete"){
                       fn();
                    }
                });
            }
        },
        each: function (obj, fn) {
            // 1.判斷是否是數(shù)組
            if(njQuery.isArray(obj)){
                for(var i = 0; i < obj.length; i++){
                   // var res = fn(i, obj[i]);
                   var res = fn.call(obj[i], i, obj[i]);
                   if(res === true){
                       continue;
                   }else if(res === false){
                       break;
                   }
                }
            }
            // 2.判斷是否是對(duì)象
            else if(njQuery.isObject(obj)){
                for(var key in obj){
                    // var res = fn(key, obj[key]);
                    var res = fn.call(obj[key], key, obj[key]);
                    if(res === true){
                        continue;
                    }else if(res === false){
                        break;
                    }
                }
            }
            return obj;
        },
        map: function (obj, fn) {
            var res = [];
            // 1.判斷是否是數(shù)組
            if(njQuery.isArray(obj)){
                for(var i = 0; i < obj.length; i++){
                    var temp = fn(obj[i], i);
                    if(temp){
                        res.push(temp);
                    }
                }
            }
            // 2.判斷是否是對(duì)象
            else if(njQuery.isObject(obj)){
                for(var key in obj){
                    var temp =fn(obj[key], key);
                    if(temp){
                        res.push(temp);
                    }
                }
            }
            return res;
        },
        // 來(lái)源: http://www.w3school.com.cn/xmldom/prop_node_nextsibling.asp
        get_nextsibling: function (n) {
            var x = n.nextSibling;
            while (x != null && x.nodeType!=1)
            {
                x=x.nextSibling;
            }
            return x;
        },
        get_previoussibling: function (n) {
            var x=n.previousSibling;
            while (x != null && x.nodeType!=1)
            {
                x=x.previousSibling;
            }
            return x;
        },
        getStyle: function (dom, styleName) {
            if(window.getComputedStyle){
                return window.getComputedStyle(dom)[styleName];
            }else{
                return dom.currentStyle[styleName];
            }
        },
        addEvent: function(dom, name, callBack) {
            if(dom.addEventListener){
                dom.addEventListener(name, callBack);
            }else{
                dom.attachEvent("on"+name, callBack);
            }
        }
    });
    // DOM操作相關(guān)方法
    njQuery.prototype.extend({
        empty: function () {
            // 1.遍歷指定的元素
            this.each(function (key, value) {
                value.innerHTML = "";
            });
            // 2.方便鏈?zhǔn)骄幊?            return this;
        },
        remove: function (sele) {
            if(arguments.length === 0){
                // 1.遍歷指定的元素
                this.each(function (key, value) {
                    // 根據(jù)遍歷到的元素找到對(duì)應(yīng)的父元素
                    var parent = value.parentNode;
                    // 通過(guò)父元素刪除指定的元素
                    parent.removeChild(value);
                });
            }else{
                var $this = this;
                // 1.根據(jù)傳入的選擇器找到對(duì)應(yīng)的元素
                $(sele).each(function (key, value) {
                    // 2.遍歷找到的元素, 獲取對(duì)應(yīng)的類型
                    var type = value.tagName;
                    // 3.遍歷指定的元素
                    $this.each(function (k, v) {
                        // 4.獲取指定元素的類型
                        var t = v.tagName;
                        // 5.判斷找到元素的類型和指定元素的類型
                        if(t === type){
                            // 根據(jù)遍歷到的元素找到對(duì)應(yīng)的父元素
                            var parent = value.parentNode;
                            // 通過(guò)父元素刪除指定的元素
                            parent.removeChild(value);
                        }
                    });
                })
            }
            return this;
        },
        html: function (content) {
            if(arguments.length === 0){
                return this[0].innerHTML;
            }else{
                this.each(function (key, value) {
                    value.innerHTML = content;
                })
            }
        },
        text: function (content) {
            if(arguments.length === 0){
                var res = "";
                this.each(function (key, value) {
                    res += value.innerText;
                });
                return res;
            }else{
                this.each(function (key, value) {
                    value.innerText = content;
                });
            }
        },
        appendTo: function (sele) {
            // 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
            var $target = $(sele);
            var $this = this;
            var res = [];
            // 2.遍歷取出所有指定的元素
            $.each($target, function (key, value) {
                // 2.遍歷取出所有的元素
                $this.each(function (k, v) {
                    // 3.判斷當(dāng)前是否是第0個(gè)指定的元素
                    if(key === 0){
                        // 直接添加
                        value.appendChild(v);
                        res.push(v);
                    }else{
                        // 先拷貝再添加
                        var temp = v.cloneNode(true);
                        value.appendChild(temp);
                        res.push(temp);
                    }
                });
            });
            // 3.返回所有添加的元素
            return $(res);
        },
        prependTo: function (sele) {
            // 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
            var $target = $(sele);
            var $this = this;
            var res = [];
            // 2.遍歷取出所有指定的元素
            $.each($target, function (key, value) {
                // 2.遍歷取出所有的元素
                $this.each(function (k, v) {
                    // 3.判斷當(dāng)前是否是第0個(gè)指定的元素
                    if(key === 0){
                        // 直接添加
                        value.insertBefore(v, value.firstChild);
                        res.push(v);
                    }else{
                        // 先拷貝再添加
                        var temp = v.cloneNode(true);
                        value.insertBefore(temp, value.firstChild);
                        res.push(temp);
                    }
                });
            });
            // 3.返回所有添加的元素
            return $(res);
        },
        append: function (sele) {
            // 判斷傳入的參數(shù)是否是字符串
            if(njQuery.isString(sele)){
                this[0].innerHTML += sele;
            }else{
                $(sele).appendTo(this);
            }
            return this;
        },
        prepend: function (sele) {
            // 判斷傳入的參數(shù)是否是字符串
            if(njQuery.isString(sele)){
                this[0].innerHTML = sele + this[0].innerHTML;
            }else{
                $(sele).prependTo(this);
            }
            return this;
        },
        insertBefore: function (sele) {
            // 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
            var $target = $(sele);
            var $this = this;
            var res = [];
            // 2.遍歷取出所有指定的元素
            $.each($target, function (key, value) {
                var parent = value.parentNode;
                // 2.遍歷取出所有的元素
                $this.each(function (k, v) {
                    // 3.判斷當(dāng)前是否是第0個(gè)指定的元素
                    if(key === 0){
                        // 直接添加
                        parent.insertBefore(v, value);
                        res.push(v);
                    }else{
                        // 先拷貝再添加
                        var temp = v.cloneNode(true);
                        parent.insertBefore(temp, value);
                        res.push(temp);
                    }
                });
            });
            // 3.返回所有添加的元素
            return $(res);
        },
        insertAfter: function (sele) {
            // 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
            var $target = $(sele);
            var $this = this;
            var res = [];
            // 2.遍歷取出所有指定的元素
            $.each($target, function (key, value) {
                var parent = value.parentNode;
                var nextNode = $.get_nextsibling(value);
                // 2.遍歷取出所有的元素
                $this.each(function (k, v) {
                    // 3.判斷當(dāng)前是否是第0個(gè)指定的元素
                    if(key === 0){
                        // 直接添加
                        parent.insertBefore(v, nextNode);
                        res.push(v);
                    }else{
                        // 先拷貝再添加
                        var temp = v.cloneNode(true);
                        parent.insertBefore(temp, nextNode);
                        res.push(temp);
                    }
                });
            });
            // 3.返回所有添加的元素
            return $(res);
        },
        replaceAll: function (sele) {
            // 1.統(tǒng)一的將傳入的數(shù)據(jù)轉(zhuǎn)換為jQuery對(duì)象
            var $target = $(sele);
            var $this = this;
            var res = [];
            // 2.遍歷取出所有指定的元素
            $.each($target, function (key, value) {
                var parent = value.parentNode;
                // 2.遍歷取出所有的元素
                $this.each(function (k, v) {
                    // 3.判斷當(dāng)前是否是第0個(gè)指定的元素
                    if(key === 0){
                        // 1.將元素插入到指定元素的前面
                        $(v).insertBefore(value);
                        // 2.將指定元素刪除
                        $(value).remove();
                        res.push(v);
                    }else{
                        // 先拷貝再添加
                        var temp = v.cloneNode(true);
                        // 1.將元素插入到指定元素的前面
                        $(temp).insertBefore(value);
                        // 2.將指定元素刪除
                        $(value).remove();
                        res.push(temp);
                    }
                });
            });
            // 3.返回所有添加的元素
            return $(res);
        },
        clone: function (deep) {
            var res = [];
            // 判斷是否是深復(fù)制
            if(deep){
                // 深復(fù)制
                this.each(function (key, ele) {
                    var temp = ele.cloneNode(true);
                    // 遍歷元素中的eventsCache對(duì)象
                    njQuery.each(ele.eventsCache, function (name, array) {
                        // 遍歷事件對(duì)應(yīng)的數(shù)組
                        njQuery.each(array, function (index, method) {
                            // 給復(fù)制的元素添加事件
                            $(temp).on(name, method);
                        });
                    });
                    res.push(temp);
                });
                return $(res);
            }else{
                // 淺復(fù)制
                this.each(function (key, ele) {
                    var temp = ele.cloneNode(true);
                    res.push(temp);
                });
                return $(res);
            }
        }
    });
    // 篩選相關(guān)方法
    njQuery.prototype.extend({
        next: function (sele) {
            var res = [];
            if(arguments.length === 0){
                // 返回所有找到的
                this.each(function (key, value) {
                    var temp = njQuery.get_nextsibling(value);
                    if(temp != null){
                        res.push(temp);
                    }
                });
            }else{
                // 返回指定找到的
                this.each(function (key, value) {
                    var temp = njQuery.get_nextsibling(value)
                    $(sele).each(function (k, v) {
                        if(v == null || v !== temp) return true;
                        res.push(v);
                    });
                });
            }
            return $(res);
        },
        prev: function (sele) {
            var res = [];
            if(arguments.length === 0){
                this.each(function (key, value) {
                    var temp = njQuery.get_previoussibling(value);
                    if(temp == null) return true;
                    res.push(temp);
                });
            }else{
                this.each(function (key, value) {
                    var temp = njQuery.get_previoussibling(value);
                    $(sele).each(function (k, v) {
                        if(v == null || temp !== v) return true;
                        res.push(v);
                    })
                });
            }
            return $(res);
        }
    });
    // 屬性操作相關(guān)的方法
    njQuery.prototype.extend({
        attr: function (attr, value) {
            // 1.判斷是否是字符串
            if(njQuery.isString(attr)){
                // 判斷是一個(gè)字符串還是兩個(gè)字符串
                if(arguments.length === 1){
                    return this[0].getAttribute(attr);
                }else{
                    this.each(function (key, ele) {
                        ele.setAttribute(attr, value);
                    });
                }
            }
            // 2.判斷是否是對(duì)象
            else if(njQuery.isObject(attr)){
                var $this = this;
                // 遍歷取出所有屬性節(jié)點(diǎn)的名稱和對(duì)應(yīng)的值
                $.each(attr, function (key, value) {
                    // 遍歷取出所有的元素
                    $this.each(function (k, ele) {
                        ele.setAttribute(key, value);
                    });
                });
            }
            return this;
        },
        prop: function (attr, value) {
            // 1.判斷是否是字符串
            if(njQuery.isString(attr)){
                // 判斷是一個(gè)字符串還是兩個(gè)字符串
                if(arguments.length === 1){
                    return this[0][attr];
                }else{
                    this.each(function (key, ele) {
                        ele[attr] = value;
                    });
                }
            }
            // 2.判斷是否是對(duì)象
            else if(njQuery.isObject(attr)){
                var $this = this;
                // 遍歷取出所有屬性節(jié)點(diǎn)的名稱和對(duì)應(yīng)的值
                $.each(attr, function (key, value) {
                    // 遍歷取出所有的元素
                    $this.each(function (k, ele) {
                        ele[key] = value;
                    });
                });
            }
            return this;
        },
        css: function (attr, value) {
            // 1.判斷是否是字符串
            if(njQuery.isString(attr)){
                // 判斷是一個(gè)字符串還是兩個(gè)字符串
                if(arguments.length === 1){
                    return njQuery.getStyle(this[0], attr);
                }else{
                    this.each(function (key, ele) {
                        ele.style[attr] = value;
                    });
                }
            }
            // 2.判斷是否是對(duì)象
            else if(njQuery.isObject(attr)){
                var $this = this;
                // 遍歷取出所有屬性節(jié)點(diǎn)的名稱和對(duì)應(yīng)的值
                $.each(attr, function (key, value) {
                    // 遍歷取出所有的元素
                    $this.each(function (k, ele) {
                        ele.style[key] = value;
                    });
                });
            }
            return this;
        },
        val: function (content) {
            if(arguments.length === 0){
                return this[0].value;
            }else{
                this.each(function (key, ele) {
                    ele.value = content;
                });
                return this;
            }
        },
        hasClass: function (name) {
            var flag = false;
            if(arguments.length === 0){
                return flag;
            }else{
                this.each(function (key, ele) {
                    // 1.獲取元素中class保存的值
                    var className = " "+ele.className+" ";
                    // 2.給指定字符串的前后也加上空格
                    name = " "+name+" ";
                    // 3.通過(guò)indexOf判斷是否包含指定的字符串
                    if(className.indexOf(name) != -1){
                        flag = true;
                        return false;
                    }
                });
                return flag;
            }
        },
        addClass: function (name) {
            if(arguments.length === 0) return this;

            // 1.對(duì)傳入的類名進(jìn)行切割
            var names = name.split(" ");
            // 2.遍歷取出所有的元素
            this.each(function (key, ele) {
                // 3.遍歷數(shù)組取出每一個(gè)類名
                $.each(names, function (k, value) {
                    // 4.判斷指定元素中是否包含指定的類名
                    if(!$(ele).hasClass(value)){
                        ele.className = ele.className + " " + value;
                    }
                });
            });
            return this;
        },
        removeClass: function (name) {
            if(arguments.length === 0){
                this.each(function (key, ele) {
                    ele.className = "";
                });
            }else{
                // 1.對(duì)傳入的類名進(jìn)行切割
                var names = name.split(" ");
                // 2.遍歷取出所有的元素
                this.each(function (key, ele) {
                    // 3.遍歷數(shù)組取出每一個(gè)類名
                    $.each(names, function (k, value) {
                        // 4.判斷指定元素中是否包含指定的類名
                        if($(ele).hasClass(value)){
                            ele.className = (" "+ele.className+" ").replace(" "+value+" ", "");
                        }
                    });
                });
            }
            return this;
        },
        toggleClass: function (name) {
            if(arguments.length === 0){
                this.removeClass();
            }else{
                // 1.對(duì)傳入的類名進(jìn)行切割
                var names = name.split(" ");
                // 2.遍歷取出所有的元素
                this.each(function (key, ele) {
                    // 3.遍歷數(shù)組取出每一個(gè)類名
                    $.each(names, function (k, value) {
                        // 4.判斷指定元素中是否包含指定的類名
                        if($(ele).hasClass(value)){
                            // 刪除
                            $(ele).removeClass(value);
                        }else{
                            // 添加
                            $(ele).addClass(value);
                        }
                    });
                });
            }
            return this;
        }
    });
    // 事件操作相關(guān)的方法
    njQuery.prototype.extend({
        on: function (name, callBack) {
            // 1.遍歷取出所有元素
            this.each(function (key, ele) {
                // 2.判斷當(dāng)前元素中是否有保存所有事件的對(duì)象
                if(!ele.eventsCache){
                    ele.eventsCache = {};
                }
                // 3.判斷對(duì)象中有沒(méi)有對(duì)應(yīng)類型的數(shù)組
                if(!ele.eventsCache[name]){
                    ele.eventsCache[name] = [];
                    // 4.將回調(diào)函數(shù)添加到數(shù)據(jù)中
                    ele.eventsCache[name].push(callBack);
                    // 5.添加對(duì)應(yīng)類型的事件
                    njQuery.addEvent(ele, name, function () {
                        njQuery.each(ele.eventsCache[name], function (k, method) {
                            method.call(ele);
                        });
                    });
                }else{
                    // 6.將回調(diào)函數(shù)添加到數(shù)據(jù)中
                    ele.eventsCache[name].push(callBack);
                }
            });
            return this;
        },
        off: function (name, callBack) {
            // 1.判斷是否沒(méi)有傳入?yún)?shù)
            if(arguments.length === 0){
                this.each(function (key, ele) {
                    ele.eventsCache = {};
                });
            }
            // 2.判斷是否傳入了一個(gè)參數(shù)
            else if(arguments.length === 1){
                this.each(function (key, ele) {
                    ele.eventsCache[name] = [];
                });
            }
            // 3.判斷是否傳入了兩個(gè)參數(shù)
            else if(arguments.length === 2){
                this.each(function (key, ele) {
                    njQuery.each(ele.eventsCache[name], function (index, method) {
                        // 判斷當(dāng)前遍歷到的方法和傳入的方法是否相同
                        if(method === callBack){
                            ele.eventsCache[name].splice(index,  1);
                        }
                    });
                });
            }
            return this;
        }
    });
    njQuery.prototype.init.prototype = njQuery.prototype;
    window.njQuery = window.$ = njQuery;
})( window );
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容