乐趣区

关于jquery:js实现jQuery的简单方法和链式操作

我用这篇文章来理一理如何用 js 去实现封装 jQuery 的简略办法。

本文 js 实现了上面 jquery 的几种办法,我将它分为 8 个小指标

  • 实现 $(“.box1”).click()办法
  • 实现 $(“div”).click()办法
  • 思考 $()中参数的三种状况
  • 实现 jq 中的 on 办法
  • 实现链式操作
  • 实现 jq 中的 eq 办法
  • 实现 jq 中的 end 办法
  • 实现 jq 中的 css 办法
有不正确的中央还望大家在评论区指出来,谢谢啦。

1. 实现 $(“.box1”).click()办法

首先,咱们定第一个小指标,就是如何一步一步去实现下方 jQuery 代码的性能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    // 同一个文件下操作的话,前面记得删除上面引入的 cdn
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
    <style> .box1 {
            width: 100px;
            height: 100px;
            background: red;
        } </style>
</head>
<body>
    <div class="box1"></div>
</body>
<script> $(".box1").click(()=>{console.log(456);
    }) </script>
</html>
复制代码 
 $(".box1").click(()=>{console.log(456);
    })
复制代码 

好了,言归正传,咱们来剖析下面 jQuery 的代码。

  • $(“.box1”) 就是实现了选择器的性能。
  • $(“.box1”).click 就是选择器 + 调用 click 办法
  • 最初在 click 外面传入函数。

第一个小指标就是本人封装 js 来实现下面代码的性能。咱们分三步走策略来实现。

  1. js 实现 $(“.box1”)
  2. 实现 $(“.box1”).click()
  3. 实现 $(“.box1”).click(() => {console.log(“123”) } )

第一步就是先用 js 实现 $(“.box1”),对吧

 // 实现 $(".box1")
    class jquery {constructor(arg) {console.log(document.querySelector(arg));
        }
    }

    function $(arg) {return new jquery(arg);
    }

    // 实现 $(".box1")
    let res =  $(".box1");
    console.log(res);
复制代码 

这样是不是就通过构建 () 办法并返回 jquery 实例,实现了 (“.box1”) 呢。

那好,接下来咱们进行第二步就是实现 $(“.box1”).click()。置信大家也看进去了,就是在 jquery 类中多了一个 click 办法。

 // 实现 $(".box1").click()
    class jquery {constructor(arg) {console.log(document.querySelector(arg));
        }

        click() {console.log("执行了 click 办法");
        }
    }

    function $(arg) {return new jquery(arg);
    }

    // 实现 $(".box1").click()
    let res =  $(".box1").click();
    console.log(res);
复制代码 

接下来,咱们进行第三步就是实现 $(“.box1”).click(() => {console.log(“123”) } )。

 // 实现 $(".box1").click(() => {console.log("123")})
    class jquery {constructor(arg) {this.element = document.querySelector(arg);
            // console.log(element);
        }

        click(fn) {this.element.addEventListener("click", fn);
        }

    }

    function $(arg) {return new jquery(arg);
    }

    // 实现 $(".box1").click(() => {console.log("123")})
    $(".box1").click(() => {console.log("123")
    });
复制代码 

到此为止,咱们实现了第一个小指标,大家是不是感觉简略呢,ok,接下来咱们持续第二个小指标。

2. 实现 $(“div”).click()办法

第二个小指标也不难,就是思考有多个 div 元素须要绑定 click 事件,咱们用 selectSelectorAll 来获取元素的话,如何解决,其实也挺简略,就是在 click 办法中多出一个循环,去获取 NodeList 中的值。我间接上代码了,大家试一试就晓得啦。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style> .box1 {
            width: 100px;
            height: 100px;
            background: red;
        }
        .box2 {
            width: 100px;
            height: 100px;
            background: blue;
        } </style>
</head>

<body>
    <div class="box1"></div>

    <div class="box2"></div>
</body>

<script> // 实现 $(".box1").click(() => {console.log("123")})
    class jquery {constructor(arg) {
            // 上面 element 存的是 NodeList 对象,它是一个类数组有 length 属性
            this.element = document.querySelectorAll(arg);
        }

        click(fn) {for(let i = 0; i < this.element.length; i++) {this.element[i].addEventListener("click", fn);
            }            
        }

    }

    function $(arg) {return new jquery(arg);
    }

    // 实现 $(".box1").click(() => {console.log("123")})
    $("div").click(() => {console.log("123")
    }); </script>

</html>
复制代码 

好了,实现两个小指标了,置信你曾经有成就感了。

3. 思考 $()中参数的三种状况

接下来第三个小指标 咱们来考虑一下 $()中参数不同的状况,我先将三种状况列出来。(可能还有其余状况,这里就不说了)

1. 状况一:就是 $()参数为字符串

 $(".box1")
复制代码 

2. 状况二:就是 $()参数为函数的状况。

 // 参数为函数
    $(function() {console.log("123");
    })
复制代码 

3. 状况三:就是 $()参数为 NodeList 对象或 selectSelect 取得的节点

 // 状况三
    $(document.querySelectorAll("div")).click(()=>{console.log("123");
    })
    $(document.querySelector("div")).click(()=>{console.log("456");
    })
复制代码 

接下来第三个小指标是手写函数来实现三种状况。首先咱们减少 addEles 办法,批改下面的 click 办法

 addEles(eles){for (let i = 0; i < eles.length; i++) {this[i] = eles[i];
            }
            this.length = eles.length;
        }

        // 实现 $(".box1").click(() => {console.log("123")}) 
        click(fn) {for(let i = 0; i < this.length; i++) {this[i].addEventListener("click", fn);
            }            
        }
复制代码 

接下来实现三种不同参数的解决办法

 constructor(arg) {

            // 状况一
            if(typeof arg === 'string') {this.addEles(document.querySelectorAll(arg));
            }else if(typeof arg === 'function') {
                // 状况二
                document.addEventListener("DOMContentLoaded", arg);
            }else {
                // 状况三
                if(typeof arg.length === 'undefined') {this[0] = arg;
                    this.length = 1;
                }else {this.addEles(arg);
                }
            }

        }
复制代码 

4. 实现 jq 中的 on 办法

接下来实现第四个小指标 实现 jq 的 on 办法

 // on 办法
        on(eventName, fn) {let eventArray = eventName.split(" ");
            // 思考多个节点
            for(let i = 0; i < this.length; i++) {
                // 思考多个事件
                for(let j = 0; j < eventArray.length; j++) {this[i].addEventListener(eventArray[j], fn);
                }
            }
        }
复制代码 

再测试下 ok 不

 // on 办法
    $("div").on("mouseover mousedown",function(){console.log("on 办法");
    })
复制代码 

5. 实现链式操作

接下来实现第五个小指标 实现 jq 的链式操作

划重点,在 on 和 click 中增加 return this 即可实现链式

 // 链式操作
        // 划重点,在 on 和 click 中增加 return this 即可实现链式
        // click 办法
        click(fn) {for(let i = 0; i < this.length; i++) {this[i].addEventListener("click", fn);
            }
            return this; 
            // console.log(this); 
        }

        // on 办法
        on(eventName, fn) {let eventArray = eventName.split(" ");
            // 思考多个节点
            for(let i = 0; i < this.length; i++) {
                // 思考多个事件
                for(let j = 0; j < eventArray.length; j++) {this[i].addEventListener(eventArray[j], fn);
                }
            }
            return this;
        }
复制代码 

6. 实现 jq 中的 eq 办法

接下来实现第六个小指标 实现 jq 中的 eq 办法

 //eq 办法
        eq(index) {return new jquery(this[index]);
        }
复制代码 

这里通过 new 一个 jquery 实现 new 的过程大家应该分明吧,咱们复习一下:

  1. 执行函数
  2. 主动创立一个空对象
  3. 将空对象的原型指向构造函数的 prototype 属性
  4. 将空对象和函数外部 this 绑定
  5. 如果 renturn 后跟着对象,返回这个对象。没跟的话就主动返回 this 对象

7. 实现 jq 中的 end 办法

实现第七个小指标 实现 jq 中的 end 办法。要实现这个性能,除了新增 end()办法,咱们还得在构造函数上实现,constructor 新增参数 root,新增属性 prevObject,并在 eq 办法这种新增参数 this。

 constructor(arg, root) {if(typeof root === "undefined") {this.prevObject = [document];
            }else {this.prevObject = root;}
        //eq 办法
        eq(index) {return new jquery(this[index], this);
        }
        //end 办法
        end() {return this.prevObject;}
复制代码 

8. 实现 jq 中的 css 办法

在 jq 中 css 能够获取款式,设置一个款式或多个款式

// 状况一 : 获取款式(只去获取第一个元素)let res =  $("div").css("background");
    console.log(res);

// 状况二(设置款式)$("div").css("background","yellow");

// // 状况三(设置多个款式)$("div").css({background:"black",width:200,opacity:0.3});
复制代码 

接下来实现 css 办法

 //css 办法

        css(...args) {if(args.length === 1) {

                // 状况一:获取款式
                if(typeof args[0] === 'string') {return this.getStyle(this[0], args[0]);
                }else {
                    // 状况三:设置多个款式
                    for(let i = 0; i < this.length; i++) {for(let j in args[0]) {this.setStyle(this[i], j, args[0][j]);
                        }

                    }
                }
            }else {
                // 状况三
                for(let i = 0; i < this.length; i++) {this.setStyle(this[i], args[0], args[1]);
                }
            }
        }    //css 办法
     css(...args) {if(args.length === 1) {
            // 状况一:获取款式
            if(typeof args[0] === 'string') {return this.getStyle(this[0], args[0]);
            }else {
                // 状况三:设置多个款式
                for(let i = 0; i < this.length; i++) {for(let j in args[0]) {this.setStyle(this[i], j, args[0][j]);
                    }

                }
            }
        }else {
            // 状况三
            for(let i = 0; i < this.length; i++) {this.setStyle(this[i], args[0], args[1]);
            }
        }
    }
复制代码 

减少 cssNumber 办法来确定不必加 px 的属性名

 //css 办法用
    $.cssNumber = {
        animationIterationCount: true,
        columnCount: true,
        fillOpacity: true,
        flexGrow: true,
        flexShrink: true,
        fontWeight: true,
        gridArea: true,
        gridColumn: true,
        gridColumnEnd: true,
        gridColumnStart: true,
        gridRow: true,
        gridRowEnd: true,
        gridRowStart: true,
        lineHeight: true,
        opacity: true,
        order: true,
        orphans: true,
        widows: true,
        zIndex: true,
        zoom: true
}
复制代码 

最初献上残缺代码,如果大哥们觉的不错,给个赞呗

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style> .box1 {
            width: 100px;
            height: 100px;
            background: red;
        }
        .box2 {
            width: 100px;
            height: 100px;
            background: blue;
            transform-origin: 0 100% 0;
            transition: 0.3s;

        }
        .box2:hover {transform: scaleX(2);
            width: 200px;
            height: 100px;
        } </style>
</head>

<body>
    <div class="box1"></div>

    <div class="box2"></div>
    <button> 点击 </button>
</body>

<script> class jquery {constructor(arg, root) {if(typeof root === "undefined") {this.prevObject = [document];
            }else {this.prevObject = root;}
            // 状况一
            if(typeof arg === 'string') {this.addEles(document.querySelectorAll(arg));
            }else if(typeof arg === 'function') {
                // 状况二
                document.addEventListener("DOMContentLoaded", arg);
            }else {
                // 状况三
                if(typeof arg.length === 'undefined') {this[0] = arg;
                    this.length = 1;
                }else {this.addEles(arg);
                }
            }

        }

        // 减少办法
        addEles(eles){for (let i = 0; i < eles.length; i++) {this[i] = eles[i];
            }
            this.length = eles.length;
        }

        // 链式操作
        // 划重点,在 on 和 click 中增加 return 即可实现链式
        // click 办法
        click(fn) {for(let i = 0; i < this.length; i++) {this[i].addEventListener("click", fn);
            }
            return this; 
            // console.log(this); 
        }

        // on 办法
        on(eventName, fn) {let eventArray = eventName.split(" ");
            // 思考多个节点
            for(let i = 0; i < this.length; i++) {
                // 思考多个事件
                for(let j = 0; j < eventArray.length; j++) {this[i].addEventListener(eventArray[j], fn);
                }
            }
            return this;
        }

        //eq 办法
        eq(index) {return new jquery(this[index], this);
        }

        //end 办法
        end() {return this.prevObject;}

        //css 办法
        css(...args) {if(args.length === 1) {

                // 状况一:获取款式
                if(typeof args[0] === 'string') {return this.getStyle(this[0], args[0]);
                }else {
                    // 状况三:设置多个款式
                    for(let i = 0; i < this.length; i++) {for(let j in args[0]) {this.setStyle(this[i], j, args[0][j]);
                        }

                    }
                }
            }else {
                // 状况三
                for(let i = 0; i < this.length; i++) {this.setStyle(this[i], args[0], args[1]);
                }
            }
        }

        getStyle(ele, styleName) {return window.getComputedStyle(ele, null)[styleName];
        }
        setStyle(ele, styleName, styleValue) {if(typeof styleValue === "number" && !(styleName in $.cssNumber)) {styleValue = styleValue + "px";}
            ele.style[styleName] = styleValue;
        }

    }

    function $(arg) {return new jquery(arg);
    }

    //css 办法用
    $.cssNumber = {
        animationIterationCount: true,
        columnCount: true,
        fillOpacity: true,
        flexGrow: true,
        flexShrink: true,
        fontWeight: true,
        gridArea: true,
        gridColumn: true,
        gridColumnEnd: true,
        gridColumnStart: true,
        gridRow: true,
        gridRowEnd: true,
        gridRowStart: true,
        lineHeight: true,
        opacity: true,
        order: true,
        orphans: true,
        widows: true,
        zIndex: true,
        zoom: true
}
    // // 实现状况一:$(".box1")
    // $("div").click(() => {//     console.log("123")
    // });

    // // 实现状况二:参数为函数
    // $(function() {//     console.log('状况 2');
    // })

    // // 状况三
    // $(document.querySelectorAll("div")).click(()=>{//     console.log("123");
    // })
    // $(document.querySelector("div")).click(()=>{//     console.log("456");
    // })

    // // on 办法
    // $("div").on("mouseover mousedown",function(){//     console.log("on 办法");
    // })

    // 链式操作
    // $("div").click(() => {//     console.log("click 办法")
    // }).on("mouseover", function() {//     console.log('链式 on 办法');
    // })

    // $("div").on("mouseover", function() {//     console.log('链式 on 办法');
    // }).click(() => {//     console.log("click 办法")
    // })

    // //eq 办法
    // $("div").eq(0).click(() => {//     console.log("eq 办法")
    // })

    //endf 办法
    // let res = $("div").eq(0).eq(0).eq(0).end();
    // console.log(res);

    //css 办法

    // 状况一 : 获取款式(只去获取第一个元素)// let res =  $("div").css("background");
    // console.log(res);

    // 状况二(设置款式)// $("div").css("background","yellow");

    // // 状况三(设置多个款式)// $("div").css({background:"black",width:200,opacity:0.3}); </script>
</html>
退出移动版