1-4、前端编程思想进阶-面向对象之实现自己的jQ库(4)

154 阅读3分钟

一、面向对象之实现自己的库

1. 课程主题 & 知识点

课程主题:

  • 定义函数&返还jQ对象
  • ready方法和原生节点处理
  • 选择器的封装
  • 封装jQ的eq方法和click方法
  • jQ的链式操作
  • 封装jQ的CSS方法
  • cssHooks的扩展功能

知识点:

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

2. jQ的特性说明 & 编码

2-1.如何实现选择器$('XXX')及click方法?以及抽象改写

// 原生js
document.querySelector(".box").onclick = function(){
    console.log("click");
}

// jq 【选择器$(“.box”) ,  click+方法】
$(".box").click(function(){
    console.log("click");
})

例:$(".box").click() $(".box")称函数执行,对象可以使用点点方式,obj.name , obj.click()等等

function $(arg){//“.box”
    return { //返还一个对象,能不能抽出-类这种形式?
        click(cb){
            document.querySelector(arg).onclick = cb;
        }
    }
}

//对象复用性不强,改写如上方法,抽离成类!(类--实例化后-就是对象)
class JQ {//类
  constructor(arg) {
    this.ele = document.querySelector(arg);
  }
  click(cb) {
    this.ele.addEventListener("click", cb);
  }
}

function $(arg) {
  return new JQ(arg);//类的实例化
}

2-2.选择器点多种情况处理?

// 选择器的多种情况处理??(1.参数不同,2.多个元素的处理情况)
$(document.querySelector("div")).click(()=>{
    console.log(111);
})

$(".box").click(function(){
    console.log("click");
})

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

2-3.多元素多事件多处理? click、mouseOver等

$(".box").on("click",function(){
    console.log("click");
})

$(".box").on("mouseover mousedown",function(){
    console.log("123"); //空格作为链接
})

// 多种情况处理 ?
// --> 多种情况间的异同区分开,判断&处理。多个元素、事件:循环绑定
// 引出链式操作 :return this;

$(".box").on("mouseover",function(){ 
        //都是一个对象 $(‘.box’)
        console.log("mouseover");
    }).on("mousedown",function(){
        console.log("mousedown");
    })
})
//多节点,多事件,所以是双循环
on(eventName,cb){
    let eventArr = eventName.split(" ");
    // 针对多个节点绑定多个事件
    // console.log(eventArr);
    for(let i=0; i<this.length; i++){
        for(let j=0; j<eventArr.length; j++){
            this[i].addEventListener(eventArr[j],cb);
        }
    }
    // 可以继续on链式操作,加return this(表示操作对象)
    return this; 
}

2-4.链式操作

如何实现链式调用?

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

  • 返还this对象
  • 返还实例化对象
//1.返还this及返还实例化对象(只能操作, 之前操作的对象)如下:
$("div").on("click",function(){ //操作是div
    console.log(111);
}).eq(0).on("click",function(){ //操作对象还是div
    console.log(222);
})
 
$("div").eq(0).on("click",function(){
    console.log(111);
})

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

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

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

记录保持上次节点: image.png

eq(index){
    //return this[index]; 拿到的是原生节点,不包含on等方法
    return new Jq(this[index],this);
    //返回了新的Jq对象
}

end(){
    return this['prevObject'];
}

get(index){
    return this[index];
}

2-5.css方法实现

// 1.对象传入 修改样式
$("div").css({width:"100px",height:"100px",background:"red"});

// 2.字符串参数

$("div").css("background","blue");

// 3.获取样式
let res = $("div").css("background");
console.log(res);

// 不定参
// 区分特新分开处理(多次判断);
css(...args){
// console.log(arguments) //打印隐藏参数
// console.log(args);

// 区分不同情况分别处理
if(args.length===1){
//1、一个参数:对象和字符串情况;
    if(typeof args[0] === "object"){
        // 1 设置多个样式 【对象传入 修改样式】
    //$("div").css({width:"100px",height:"100px",background:"red"});
        for(let i=0;i<*this*.length;i++){
            for(let j in *args*[0]){// 多个元素
                this.#setStyle(this[i], j, args[0][j]);
            }
        }
    }else{
        //3 获取一个样式:多个元素只会获取第一个元素样式 【获取样式】
        //let res = $("div").css("background");
        return this.#getStyle(this[0],args[0])
    }
}else{
// 2、两个参数 :设置一个样式 【字符串参数】
    // $("div").css("background","blue");
    // 多个元素设置一个样式
        for(let i=0;i<this.length;i++){
            this.#setStyle(this[i], args[0], args[1]);
        }
    }
    return this;
}

2-6.提高扩展性 wh: “px”

.cssNumber.whtrue;
$("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");
#getStyle(ele, styleName){
    if(styleName in $.cssHooks){
        return $.cssHooks[styleName].get(ele);
    }
    return getComputedStyle(ele, null)[styleName];
}
 
#setStyle(ele, styleName, styleValue){//提高扩展性
    if(typeof styleValue === "number" && !$.cssNumber[styleName]){
        styleValue = styleValue + "px";
    }

    if(styleName in $.cssHooks){
        $.cssHooks[styleName].set(ele, styleValue);
    }
    ele.style[styleName] = styleValue;

}
$.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 = {};
function $(arg){
    return new Jq(arg);
}

2-7.课后练习

(1)实现一个animate方法?

$("button").on("click",function(){
    $(".box").animate({width:"600px"},function(){
        console.log("运动完成");
    });
})

//封装:编码
//自定义动画函数
  animate(...args) {
    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";

    console.log(...args); //{width:"300px"},function(){console.log("运动完成"); }
    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]);
      }
    }
    console.log(this); //0:div.box  1:div.box

    //最后一个参数的函数,动画完成之后—执行函数
    if (typeof args[args.length - 1] === "function") {
      document.addEventListener("transitionend", args[args.length - 1]);
    }
  }

(2)Deferred?

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

    $("div").animate({width:"300px"},function(){
        console.log("运动完成");
    })

})

image.png

(3)$.callbacks( )实现 deferred ?

image.png