Skip to content

面向对象封装自己的库

主题

一、定义函数返还JQ对象

二、ready方法和原生节点处理

三、选择器器封装

四、封装JQ的eq方法

五、封装JQ的click方法

六、jQ中的链式操作

七、封装JQ的css方法

八、cssHooks扩展功能

知识点

  • 对象成员与类成员
  • 判断类型
  • 链式调用实现
  • 正则表达式

jquery特性说明

​ 知己知彼,百战不殆;想要知道jq功能如何实现,先要了解其特性;

###如何实现链式调用

根据对象的特性,发还jq对象;

  • 返还this对象
js
class Jq{
    click(){
        console.log("click...");
        return this;
    }
}
let myjq = new Jq();
myjq.click().click();
  • 返还实例化对象

处理ready和原生节点

  • 针对ready方法做兼容处理
  • 原生节点直接保存
js
if (typeof arg === "string") {
    let els = document.querySelectorAll(arg);
} else if (typeof arg === 'function') {
    window.addEventListener("DOMContentLoaded",arg,false);
} else {
    if(typeof arg.length === 'undefined'){
        // 一个对象;
        this[0] = arg;
        this.length = 1;
    }else{
        // 对象类数组;
        this.addEle(arg);
    }
}

###选择器器封装

  • $(".box")选择节点实现

封装jq的eq方法

​ 注意返还对象,实现链式调用

js
 eq(index){
     // 继续操作
     // return this[index];
     return new Jq(this[index],this);
 }

###实现end方法

返还上次操作的节点;

js
end(){
    return this.prevObject;
}

实现jq里的click方法

绑定click事件

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

实现on方法

和click方法类似,可以处理多个事件;

实现css方法

  • 获取样式封装

  • 设置样式封装

    • cssNumber

      js
      {
              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
      }

使用类仿JQuery功能封装

myjqtest.html

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./myjq.js"></script>
    <style>
        .box {
            background: red;
            width: 100px;
            height: 100px;
        }

        .box2 {
            background: yellow;
        }
    </style>
</head>
<body>
    <div class="box" style="background: red;">111</div>
    <div class="box" style="background: blue;">222</div>
    
    <h1>自己的jq</h1>
    <!-- <button>点击1</button>
    <button>点击2</button> -->
    <div class="box">div1</div>
    <!-- <div class="box2">div2</div> -->
    <button>点击</button>
</body>
<script>
    // jq 
    // $(".box").click(function(){
    //     console.log("click");
    // })
 
//     $(document.querySelector("div")).click(()=>{
//     console.log(111);
// })

// $(function(){
//     console.log("加载完毕");
// })
    

// let res =  $(".box");
// console.log(res);
// $(".box").click(()=>{
//     console.log("click");
// })
// $(document.querySelectorAll(".box")).click(()=>{
//     console.log(123);
// })

// $(".box").on("mouseover mousedown",function(){
//     console.log("123");
// })
// $(".box").on("mouseover",function(){
//     console.log("mouseover");
// }).on("mousedown",function(){
//     console.log("mousedown");
// })
// let res =  $(".box").eq(0);
// // console.log(res.on);
// // res.on();
// res.on("click",function(){
//     console.log(123);
// })

// 回滚
// $("div").eq(0).eq(0).end().end().on("click",function(){
//     console.log(123);
// })

// let res = $("div").eq(0).eq(0);
// console.log(res);

    
// $("div").css({width:"100px",height:"100px",background:"blue"});
// let res =  $("div").css("background");
// console.log(res);

// $("div").css("background","black");
// $("div").css({width:100,height:"100px",background:"red",opacity:.3});

$.cssHooks.wh = {
    get(ele){
        console.log("get",ele);
        return getComputedStyle(ele,null)['width'] + "-" + getComputedStyle(ele,null)['height'];
    },
    set(ele,styleValue){
        console.log("set",ele,styleValue);
        ele.style['width'] = styleValue;
        ele.style['height'] = styleValue;
    }
}
// $("div").css("wh","300px");
// let res =  $("div").css("wh");
// console.log(res);
$("div").css("wh","300px");

    
// jq-->js框架
    // 一、原生实现如下功能??[fn1,fn2...]
    // $("button").click(()=>{});
    // $("button").click(() => {
    //     console.log(123);
    // })
    // console.log($("button"));
    // $("button").click(()=>{
    //     console.log(123);
    // })
    // console.log(document.querySelectorAll("button"));
    // console.log(document.querySelector("button"));
    // $(document.querySelector("button")).click(() => {
    //     console.log(123);
    // })

    // $("button").on("mouseover mousedown", () => {
    //     console.log("执行了");
    // })
    // $("button").eq(1).eq(0).on("click",function(){
    //     console.log("click");
    // })
    // console.log($("button").eq(0).eq(0));
    // $("button").eq(0).eq(0).end().end().on("click",function(){
    //     console.log("click");
    // })
    // let res = $("div").css("background");
    // console.log(res);
    // 外部扩展
    // $.cssNumber.wh = true;
    // $(".box").css("background","blue");
    // $(".box").css({"opacity":0.4});
    // $.cssHooks.wh = {
    //     get(ele) {
    //         // console.log(ele);
    //         return getComputedStyle(ele, null)['width'] + "-" + getComputedStyle(ele, null)['height'];
    //     },
    //     set(ele, styleValue) {
    //         ele.style['width'] = styleValue;
    //         ele.style['height'] = styleValue;
    //     }
    // }
    // // let res =  $(".box").css("wh")  // get 
    // // console.log(res);
    // $(".box").css("wh", "200px");

// 作业:实现一个aniamte ; 不基于库或者插件
$("button").click(function(){
    // slow fast nomal  
//    $("div").animate({width:"300px"},2000,function(){
//        console.log("运动完成");
//    });
    $("div").animate({width:"300px"},function(){
        console.log("运动完成");
    })
})
</script>
</html>

myjq.js

js
// function $(arg){
//     return {
//         click(cb){
//             document.querySelector(arg).onclick = cb;
//         }
//     }
// }
// const config = {
//     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
// }

class Jq{
    constructor(arg,root){
        if(typeof root === "undefined"){
            this['prevObject'] = [document];
        }else{
            this['prevObject'] = root;
        }
        
        // 通过类型区分不同的情况分别处理
        if (typeof arg === 'string') {
            // 字符串情况
            // this[0] = document.querySelector(arg);
            let eles = document.querySelectorAll(arg);
            // 多个元素保存
            this.#addEles(eles);
        } 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){
        // console.log(eles)
        for(let i=0;i<eles.length;i++){
            this[i] = eles[i];
        }
        this.length = eles.length;
    }
    click(fn) {
        // 多个元素绑定
        for (let i = 0; i < this.length; i++) {
            this[i].addEventListener("click", fn);
        }
        // this[0].addEventListener("click",fn);

    }
    on(eventName, fn) {
        let eventArr = eventName.split(" ");
        // 多层循环
        // 多个元素
        for (let i = 0; i < this.length; i++) {
            // 多个事件
            for (let j = 0; j < eventArr.length; j++) {
                this[i].addEventListener(eventArr[j], fn);
            }
        }
        return this;
    }
    eq(index) {
        // 对象不变链式
        // return this;
        // 对象有改变
        return new Jq(this[index], this);
    }
    end() {
        return this['preObject'];
    }
    css(...args) {
        // console.log(arguments)
        //不定参问题 
        if (args.length === 1) {
            // 1、3 情况
            if (typeof args[0] === 'string') {
                // 1情况
                return this.#getStyle(this[0], args[0]);
            } else {
                // 3情况 对象 多个节点 多个样式
                for(let i=0;i<this.length;i++){
                    for(let j in args[0]){
                        this.#setStyle(this[i],j,args[0][j]);
                    }
                }
            }
        } else {
            // 2情况 字符串
            for(let i=0;i<this.length;i++){
                this.#setStyle(this[i],args[0],args[1]);
            }
        }
    }
    #getStyle(ele, styleName) {
        // 调取cssHooks里的 get
        if(styleName in $.cssHooks){
            return $.cssHooks[styleName].get(ele);
        }
        return getComputedStyle(ele, null)[styleName];
    }
    #setStyle(ele,styleName,styleValue){
        // console.log(styleName in $.cssNumber);
        if(typeof styleValue === "number" && !(styleName in $.cssNumber)){
            styleValue = styleValue + "px";
        }
        // 调取cssHooks里的 set
        if(styleName in $.cssHooks) {
            $.cssHooks[styleName].set(ele,styleValue);
        }
        ele.style[styleName] =  styleValue;
    }
    animate(...args){
        let timer = 500;
        if(typeof args[1] !== "function"){
            if(typeof args[1] === 'string'){
                switch( args[1]){
                    case 'slow':
                        timer = 1000;
                        break;
                    case 'fast':
                        timer = 200;
                        break;
                    case 'nomal':
                        timer = 600;
                        break;
                }
            }else if(typeof args[1] === "number"){
                timer = args[1];
            }
        }
        let timerSecond = timer/1000 + "s";

        for(let i=0;i<this.length;i++){
            this[i].style.transition = timerSecond+' all';
            for(let j in args[0]){
                this.#setStyle(this[i],j,args[0][j]);
            }
        }

        if(typeof args[args.length-1] === "function"){
            document.addEventListener("transitionend",args[args.length-1]);
        }

    }
}


function $(arg) {
    return new Jq(arg);
    // return {
    //     click(fn){
    //        document.querySelector(arg).onclick = function(){
    //             fn && fn();
    //             // fn();
    //        } 
    //     }
    // }
}

// 给未来扩展 对外暴露了配置
$.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
}

$.cssHooks = {};
// fn && fn() 等同于下面
// if(fn){
//     fn();
// }

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

总结

  • 类及对象

  • 链式调用

  • 对象的包装

  • 拓展功能

Released under the MIT License.