為什麼放棄jQuery

CodingDangerously發表於2020-10-15

一. 前言

首先,直接操作dom的程式設計方式已經成為過去,資料驅動才是正途!
其次,不一定非要捨棄jQuery,只是可以,選擇權在自己手上!
下面只是就事論事

二. 落幕

2018年7月 全球最大的同性交友社群(Github)被微軟收購後的 52 天,改版並放棄了 jQuery 。這一舉動讓我等搬運工陷入了沉思。

三.Why?

隨著ECMAScript標準的更新,原生js已經可代替jQuery,給我babel一個面子,不要再說相容不支援的話!
下面舉兩個比較常用的方面來說明:

  • jQuery Api可以使用原生輕鬆實現
  • 使用 fetch 來代替 ajax;
    Fetch API 是基於 Promise 設計,更符合目前的非同步解決方案。什麼是目前的非同步解決方案?翻看上一篇async & await

四.具體實現對比(部分)

1.選擇器

    //jq
    $("#a .b");

    //Native
    document.querySelectorAll("#a .b");

2.插入

    //jq
    $(selector).append(html);
    //prepend
    //before
    //after

    //Native
    document.querySelectorAll(selector).insertAdjacentHTML("beforeend", html);
   //beforebegin 開始標籤之前 before
   //afterbegin  開始標籤之後 prepend
   //beforeend  結束標籤之前 append
   //afterbegin  結束標籤之後 after

3.類操作

    //jq
    $(selector).addClass(className);
    //hasClass
    //removeClass
    //toggleClass

    //Native
    document.querySelectorAll(selector).classList.add(className, className, className...);
   //contains(className) 檢測是否存在
   //removeClass(className, className, className...) 刪除
   //toggle(className, true|false) 切換

4.ajax

    //jq
    $.ajax({
        //.................
    });

    //Native
    (async () => {
     try{
        const res = await req(url, {headers: {Accept: "text/html"}});
        if(......){
           .......
        }
      } catch {
      
      }
    }());

    function req(url, data) {    //自己封裝,僅供參考
      let sendurl = url;
      let setting = {
          method: data.type ? data.type : "get",
          headers: new Headers({
              "Accept": "application/json, text/javascript, */*; q=0.01",
              "Pragma": "no-cache",
              "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
              "X-Requested-With": "XMLHttpRequest"
      }),
      credentials: "include"
    };

    if(data.headers){
        const headers = setting.headers;
        for(let attr in data.headers){
            if(headers.has(attr)){
                headers.set(attr, data.headers[attr]);
            } else {
                headers.append(attr, data.headers[attr]);
            }
        }
    }

    if (setting.method == "post") {
        setting.body = data.param ? paramData(data.param) : "";
    } else {
        sendurl = sendurl + (data.param ? "?" + paramData(data.param) : "");
    }

    return fetch(sendurl, setting).then((response) => {
          if (response.status >= 200 && response.status < 300) {
            return response;
          } else {
              throw new Error(response.statusText);
          }
       }).then((response) => {
         const accept = setting.headers.get("accept");
         if(accept.includes("/json")){
            return response.json();
         } else if(accept.includes("/html")){
            return response.text();
         }
      });
    }

五.原生實現類jQuery的庫

上手才是關鍵,下面實現了部分jQuery的Api(程式碼構建編譯部分省略),可能功能有所差異,但是就是這個味兒~

<!DOCTYPE html>
<html lang="en">
<title>test</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<head>
</head>
<body>
<div class="test" actid="111"></div>
</body>
<script>
class xy {
    constructor(selector){
        this.dom = document.querySelectorAll(selector);
        this.length = document.querySelectorAll(selector).length;
    }

    eq(index){
        this.dom = [this.dom[index]];
        return this;
    }

    attr(name){
        return this.dom[0].getAttribute(name);
    }

    children(index){
        let childrenList = [];
        for(let i = 0;i < this.dom.length;i++){
            childrenList.push(this.dom[i].children);
        }
        
        let arr = [];
        for(let i = 0;i < childrenList.length;i++){
            arr.push(index != undefined ? childrenList[i][index] : childrenList[i]);
        }

        return arr.length > 1 ? arr : arr[0];
    }

    append(htmlStr){
        // for(let i = 0;i < this.dom.length;i++){
        //     this.dom[i].insertAdjacentHTML("beforeend", htmlStr);
        // }
        this.circulationFun("dom.insertAdjacentHTML('beforeend', '" + htmlStr + "')");
    }

    html(htmlStr){
        this.circulationFun("dom.innerHTML = '" + htmlStr.replace(/\s*/g,"") + "'");
    }

    remove(){
        this.circulationFun("dom.parentNode.removeChild(dom)");
    }

    addClass(className){
        this.classFun("add", className);
    }

    removeClass(className){
        this.classFun("remove", className);
    }

    toggleClass(className){
        this.circulationFun("dom.classList.toggle('" + className + "')");
    }

    classFun(order, className){
        const classArr = className.split(" ");
        let code = "dom.classList." + order + "(";
        for(let i = 0;i < classArr.length;i++){
            code += "'" + classArr[i] + "',";
        }
        code = code.substr(0, code.length - 1);
        code += ")";
        this.circulationFun(code);
    }

    circulationFun(code){
        for(let i = 0;i < this.dom.length;i++){
            new Function("dom", "i", code)(this.dom[i], i);
        }
    }

    //你可以不停的去擴充套件
}

function $xy(selector){
    return new xy(selector);
}

$xy(".test").attr("actid");
//output 111
</script>

相關文章