范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

请别再用jQuery了!

  大家好,很高兴又见面了,我是" 前端‬进阶 ‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
  前端‬进阶
  今天在逛Github时无意间发现一个仓库《You Dont Need jQuery》。打开来看,发现很有意思!而且作者列举了很多jQuery常用的方法以及原生实现,因此这篇文章将以此展开。话不多说,直接开始!
  关于更多jQuery的讨论可以阅读文末我的另一篇文章《18岁了!老伙计jQuery过的怎样?》前言
  前端发展迅速,现代浏览器已经实现了大量足以用于生产的 DOM/BOM API。 不必从头开始学习 jQuery 来进行 DOM 操作或其他类型事件处理。 与此同时,由于 React、Angular 和 Vue 等前端库的普及,直接操作 DOM 并非最好的方法。 该项目总结了 jQuery 方法的原生 Javascript 替代方法,并支持 IE 10+。
  ℹ️ 注意:本文并非否定jQuery,而是探讨是否可以在没有jQuery的场景下实现功能原生实现方案并非在所有场景下都完全等效jQuery,建议做浏览器兼容性测试。1.jQuery选择器
  可以使用 document.querySelector 或 document.querySelectorAll 代替常见的jQuery选择器,如 class、id 或 attribute。 不同之处在于:document.querySelector 返回第一个匹配的元素document.querySelectorAll 将所有匹配的元素作为 NodeList 返回。 可以使用 Array.prototype.slice.call(document.querySelectorAll(selector)); 将其转换为 Array。如果没有匹配的元素,jQuery 和 document.querySelectorAll 将返回 [],而 document.querySelector 将返回 null。
  注意:document.querySelector 和 document.querySelectorAll 非常慢,如果想获得最佳性能,可以使用 document.getElementById、document.getElementsByClassName 或 document.getElementsByTagName方法。
  比如下面的jQuery方法都可以考虑使用原生方法来替代:// jQuery $("selector"); // 原生替代方法 document.querySelectorAll("selector");
  class选择器:// jQuery $(".class"); // 原生替代方法 document.querySelectorAll(".class"); // 原生替代方法 document.getElementsByClassName("class");
  id选择器:// jQuery $("#id"); // 原生替代方法 document.querySelector("#id"); // 或者 document.getElementById("id"); // 或者 window["id"]
  属性选择器:// jQuery $("a[target=_blank]"); // 原生替代方法 document.querySelectorAll("a[target=_blank]");
  子级选择器:// jQuery $el.find("li"); // 原生替代方法 el.querySelectorAll("li");
  所有兄弟元素 // jQuery $el.siblings(); // 原生替代方法 -  Edge13+ [...el.parentNode.children].filter((child) =>   child !== el ); // 原生替代方法-  Edge13+ Array.from(el.parentNode.children).filter((child) =>   child !== el ); // 原生替代方法 - IE10+ Array.prototype.filter.call(el.parentNode.children, (child) =>   child !== el );
  前面兄弟元素:// jQuery $el.prev(); // 原生替代方法 el.previousElementSibling;
  后面兄弟元素:// jQuery $el.next(); // 原生替代方法 el.nextElementSibling;
  所有前面兄弟元素:// jQuery $el.prevAll($filter); // 原生替代方法 function getPreviousSiblings(elem, filter) {   var sibs = [];   while (elem = elem.previousSibling) {       if (elem.nodeType === 3) continue;        // 忽略text类型       if (!filter || filter(elem)) sibs.push(elem);   }   return sibs; }
  所有后面兄弟元素:// jQuery $el.nextAll($filter); // 原生替代方法 function getNextSiblings(elem, filter) {         var sibs = [];         var nextElem = elem.parentNode.firstChild;         do {             if (nextElem.nodeType === 3) continue;            // 忽略文本             if (nextElem === elem) continue;             // 忽略自己             if (nextElem === elem.nextElementSibling) {                 if (!filter || filter(elem)) {                     sibs.push(nextElem);                     elem = nextElem;                 }             }         } while(nextElem = nextElem.nextSibling)         return sibs;     }
  closest方法(通过提供的选择器返回第一个匹配的元素,从当前元素向上遍历它在 DOM 树中的祖先):// jQuery $el.closest(selector); // 原生替代方法,不支持IE el.closest(selector); // 原生替代方法 - IE10+ function closest(el, selector) {   const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;   while (el) {     // while循环一直往上寻找     if (matchesSelector.call(el, selector)) {       return el;     } else {       el = el.parentElement;     }   }   return null; }
  jQuery的parentsUntil方法:// jQuery $el.parentsUntil(selector, filter); // 原生替代方法 function parentsUntil(el, selector, filter) {   const result = [];   const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;   // 使用matchs方法   el = el.parentElement;   while (el && !matchesSelector.call(el, selector)) {     if (!filter) {       result.push(el);     } else {       if (matchesSelector.call(el, filter)) {         result.push(el);       }     }     el = el.parentElement;   }   return result; }2.jQuery的CSS & Style操作方法获取/设置Style// jQuery $el.css("color");  // 原生替代方法 // 注意: 已知错误,如果样式值为"auto",将返回"auto" const win = el.ownerDocument.defaultView; // null 表示不返回伪样式 win.getComputedStyle(el, null).color;  // 原生替代方法 el.style.color = "#f01";添加/移除/判断/toggle类// jQuery $el.addClass(className); // 原生替代方法 el.classList.add(className); // 添加class el.classList.remove(className); // 移除class el.classList.contains(className); // 包含class el.classList.toggle(className); // toggle classPosition & Offset// jQuery $el.position(); // 原生替代方法 { left: el.offsetLeft, top: el.offsetTop } // 获取offset function getOffset (el) {   const box = el.getBoundingClientRect();   return {     // 保持兼容     top: box.top + window.pageYOffset - document.documentElement.clientTop,     left: box.left + window.pageXOffset - document.documentElement.clientLeft   }; }ScrollTop// jQuery $(window).scrollTop(); // 原生替代方法 (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;3.DOM操作移除元素// jQuery $el.remove(); // 原生替代方法 el.parentNode.removeChild(el);get/set HTML// jQuery $el.html(); // 原生替代方法 el.innerHTML; // jQuery设置html $el.html(htmlString); // 原生替代方法设置html el.innerHTML = htmlString;append方法// jQuery:DOMString 和 Node 对象的统一语法 $parent.append(newEl | "Hello World"); // 原生方法:不同语法 parent.insertAdjacentHTML("beforeend", "Hello World"); parent.appendChild(newEl); // Native (ES6-way):统一语法 parent.append(newEl | "Hello World");prepend方法// jQuery:DOMString 和 Node 对象的统一语法 $parent.prepend(newEl | "Hello World"); // 原生方法:不同语法 parent.insertAdjacentHTML("afterbegin", "Hello World"); parent.insertBefore(newEl, parent.firstChild); //  Native (ES6-way):统一语法 parent.prepend(newEl | "Hello World");insertBefore// jQuery $newEl.insertBefore(selector); //  原生方法 el.insertAdjacentHTML("beforebegin ", "Hello World"); // 原生 (元素) const el = document.querySelector(selector); if (el.parentNode) {   // 父元素的insertBefore   el.parentNode.insertBefore(newEl, el); }insertAfter// jQuery $newEl.insertAfter(selector); // 原生 (HTML字符串) el.insertAdjacentHTML("afterend", "Hello World"); // 原生 (元素) const el = document.querySelector(selector); if (el.parentNode) {   // 利用父元素的insertBefore   el.parentNode.insertBefore(newEl, el.nextSibling); }wrap// jQuery $(".inner").wrap(""); //  原生方法 Array.from(document.querySelectorAll(".inner")).forEach((el) => {   const wrapper = document.createElement("p");   wrapper.className = "wrapper";   el.parentNode.insertBefore(wrapper, el);   // 父元素的insertBefore   wrapper.appendChild(el); });replaceWith// jQuery $(".inner").replaceWith("");  //原生替代方法- >= Edge17+ Array.from(document.querySelectorAll(".inner")).forEach((el) => {   const outer = document.createElement("p");   outer.className = "outer";   el.replaceWith(outer); }); // 原生替代方法 Array.from(document.querySelectorAll(".inner")).forEach((el) => {   const outer = document.createElement("p");   outer.className = "outer";   // 调用父元素的replaceChild   el.parentNode.replaceChild(outer, el); });4.jQuery的Ajax请求
  Fetch API 是替代 XMLHttpRequest 执行 ajax 的新标准。 它适用于 Chrome 和 Firefox,您可以使用 polyfills 使其适用于旧版浏览器。
  在 IE9+ 上可以使用 github/fetch 或在 IE8+ 上使用 fetch-ie8,fetch-jsonp 来发出 JSONP 请求。// jQuery $(selector).load(url, completeCallback) // 原生替代方法 fetch(url).then(data => data.text()).then(data => {   document.querySelector(selector).innerHTML = data }).then(completeCallback) // POST方法 await fetch("/my/url", {   method: "POST",   headers: {     "Content-Type": "application/json"   },   body: JSON.stringify(data) });5.事件DOMContentLoaded  // jQuery   $(document).ready(eventHandler);    // 原生替代方法   // 检查 DOMContentLoaded 是否已经完成   if (document.readyState !== "loading") {     eventHandler();   } else {     document.addEventListener("DOMContentLoaded", eventHandler);   }    // 原生替代方法    // 示例 2 - 三元运算符    // 异步检查 DOMContentLoaded 是否已经完成   (async function() {     (document.readyState !== "loading") ?       eventHandler() : document.addEventListener("DOMContentLoaded",         function() {           eventHandler();          // 事件处理函数         });   })();   // 原生替代方法   // 示例 3 - 三元运算符    //非异步检查 DOMContentLoaded 是否已经完成   (function() {     (document.readyState !== "loading") ?       eventHandler() : document.addEventListener("DOMContentLoaded",         function() {           eventHandler();           // 事件处理函数         });   })();绑定/移除事件// jQuery $el.on(eventName, eventHandler); // 添加:原生替代方法 el.addEventListener(eventName, eventHandler); // jQuery $el.off(eventName, eventHandler); // 移除:原生替代方法 el.removeEventListener(eventName, eventHandler);trigger事件// jQuery $(el).trigger("custom-event", {key1: "data"}); // 通过CustomEvent原生方法替代jQuery的trigger方法  if (window.CustomEvent) {   const event = new CustomEvent("custom-event", {detail: {key1: "data"}}); } else {   const event = document.createEvent("CustomEvent");   // 构造CustomEvent实例   event.initCustomEvent("custom-event", true, true, {key1: "data"}); } // 调用dispatchEvent发布事件 el.dispatchEvent(event);6.jQuery的Promise方法
  Promise 表示异步操作的最终结果。 jQuery 有自己的方式来处理Promise。本机 JavaScript 实现了一个精简的最小 API 来根据 Promises/A+ 规范处理 promises。 done, fail, always
  done 在 promise 被resolve时被调用,fail 在 promise 被reject时被调用,当 promise 被解决或被拒绝时always被调用。 // jQuery $promise.done(doneCallback).fail(failCallback).always(alwaysCallback) // Promise原生替代方法 promise.then(doneCallback, failCallback).then(alwaysCallback, alwaysCallback)when
  when 用于处理多个promise。当所有promise都resolve时,它将resolve,如果任何一个被拒绝,它就会拒绝。 // jQuery $.when($promise1, $promise2).done((promise1Result, promise2Result) => { }); // when原生替代方法 Promise.all([$promise1, $promise2]).then([promise1Result, promise2Result] => {});Deferred
  是jQuery一种创建Promise的方式。 // jQuery function asyncFunc() {   const defer = new $.Deferred();   setTimeout(() => {     if(true) {       defer.resolve("some_value_computed_asynchronously");     } else {       defer.reject("failed");     }   }, 1000);    return defer.promise(); } // 原生替代方法 function asyncFunc() {   return new Promise((resolve, reject) => {     setTimeout(() => {       if (true) {         resolve("some_value_computed_asynchronously");       } else {         reject("failed");       }     }, 1000);   }); }  // 通过实现jQuery的Deferred // 注意:jQuery的Deferred是它实现Promise能力的基础 function defer() {   const deferred = {};   const promise = new Promise((resolve, reject) => {     deferred.resolve = resolve;     deferred.reject = reject;   });   deferred.promise = () => {     return promise;   };   return deferred; } // asyncFunc 函数伺机调用resolve/reject方法 function asyncFunc() {   const defer = defer();   setTimeout(() => {     if(true) {       // resolve       defer.resolve("some_value_computed_asynchronously");     } else {       // reject       defer.reject("failed");     }   }, 1000);   return defer.promise(); }7.jQuery实现Animation动画Show & Hide// jQuery $el.show(); $el.hide(); // 原生替代方法 // 更多信息参考链接:https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L363 el.style.display = ""|"inline"|"inline-block"|"inline-table"|"block"; el.style.display = "none";toggle// jQuery $el.toggle(); // 原生替代方法 if (el.ownerDocument.defaultView.getComputedStyle(el, null).display === "none") {  // 设置display属性值   el.style.display = ""|"inline"|"inline-block"|"inline-table"|"block"; } else {   el.style.display = "none"; }FadeIn & FadeOut// jQuery $el.fadeIn(3000); $el.fadeOut(3000); // 原生替代方法:fadeOut function fadeOut(el, ms) {   if (ms) {     el.style.transition = `opacity ${ms} ms`;     el.addEventListener(       "transitionend",       // 动画结束       function(event) {         el.style.display = "none";       },       false     );   }   el.style.opacity = "0"; } // 原生替代方法:fadeIn function fadeIn(elem, ms) {   elem.style.opacity = 0;   if (ms) {     let opacity = 0;     const timer = setInterval(function() {       // setInterval调用       opacity += 50 / ms;       if (opacity >= 1) {         clearInterval(timer);         opacity = 1;       }       // 设置opacity       elem.style.opacity = opacity;     }, 50);   } else {     elem.style.opacity = 1;   } }SlideUp & SlideDown// jQuery $el.slideUp(); $el.slideDown(); // 原生替代方法 const originHeight = "100px"; el.style.transition = "height 3s"; // 原生替代方法:slideUp el.style.height = "0px"; // 原生替代方法:slideDown el.style.height = originHeight;8.本文总结
  本文主要和大家介绍jQuery的很多常用方法如何使用原生方法来替代,比如:选择器、动画、Promise、事件、Ajax、DOM操作等等,从而引出"你可能不需要jQuery"的结论。当然,每个人都会有不同的看法。如果你觉得引入jQuery的收益对于你的项目很大,那么你还是可以坚持使用它。
  同时,文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。参考资料
  https://github.com/camsong/You-Dont-Need-jQuery
  http://www.kehuanxianshi.com/work/JavaScript/now-ever-might-not-need-jquery.html
  https://www.toutiao.com/article/7198323737454723622/
  https://youmightnotneedjquery.com/
  https://medium.com/@navneet.sahota/you-dont-need-jquery-ec070bc75238
  图片版权:来自Navneet Singh的文章《You don’t need jQuery》!

军事行动第五天东部战区继续位台岛周边海空域进行实战化联合演训,重点组织联合反潜和对海突击行动。8月8日,中国人民解放军东部战区,继续位台岛周边海空域进行实战化联合演训,重点组织联合反潜和对海突击孙怡离婚,从野模到京圈太子妃,这一仗王京花赢麻了8月8日一大早,孙怡董子健官宣离婚的消息突降热搜。孙怡和董子健一向作为圈中的金童玉女,是无数网友心中的模范夫妻。这消息一出,无数吃瓜群众纷纷表示震惊!据悉,孙怡和董子健两人于201赚麻了当事人回应滞留三亚7天将花18万一家13口被拘留三亚的当事方发表了讲话一个十三人滞留在三亚,并声称一名13名囚犯在三亚。T。8月7日,三亚突发疫情,约有80,000多名游客滞留在当地。由于疫情改为6号,航班取消了台湾艺人立场惹争议?国台办任何分裂者绝没有好下场最近大众关注对岸的情绪高涨。对中国来说,台湾问题是二十多亿中国人的心病和遗憾。如今佩洛西窜访台湾,这个问题必然要加快被解决。2日晚,很多明星们也都出来表明了态度和立场。其中,作为台明确立场了?粉丝群名被改成一个中国后,炎亚纶退出群聊引热议生而为人,就要有自己的立场,作为中华民族的儿女,被这片土地滋养长大,接受着祖国母亲的保护和依靠,就应该坚定的站在自己的母亲这一边,这是作为一个国人应该有的底线。炎亚纶因为飞轮海组合王心凌立场获央视认可!雨神打脸质疑者,炎亚纶退群再惹风波王心凌立场获央视认可!雨神打脸质疑者8月4日,央视文艺官方账号晒出了一张央视七夕晚会节目单,在西安昆明池新余仙女湖两地与全国人民一起泛舟七夕夜,诗画利乐情。在该节目单中,近日备受网1975年蒋介石邀请毛主席访台,毛主席小平同志代替我去台湾自1969年出了一场车祸后,蒋介石的身体和精神状态已经大不如前了。虽然表面上,他没有放弃反攻大陆的痴心妄想,但内心深处其实早已十分清醒地认识到加快经济建设,提高民众生活水平得以保住8月起有些人养老金将暂停发放!领过的钱也要退还,有你吗?点击上方声音按钮,可同步收听全文播报养老金开始严查!8月起有些人待遇要暂停发放,领过的钱也要退还,希望其中没有你炎热的8月开始了,大家的养老金已经补发到位并且已经按照新标准开始发放演练是否可能转为攻台实战?佩洛西窜访台湾后,我方第一时间就公布了东部战区4天6区域的围台演习,今天中午,演习准时开始,第一波已经取得了预期效果。那么这次演习是否有转成收复台湾实战的可能呢?个人认为是完全存在50岁后才懂与兄弟姐妹断联的人,已做好3种准备作者丨同言首先,我想说一个结论兄弟姐妹间的断联,肯定没有这么容易。有的时候,我在网上看到一些人吐槽亲情,或者兄弟姐妹间的关系时,总是有人提出建议,说这样的亲情关系,还不如不要,趁早西行纪大结局,光暗之争尚未结束,原始玉尊出场,穷奇大电影来袭在西行纪动画第四季中,天界光暗之战拉开序幕,古龙与西行小队也是激烈开打,官方采用两段式叙述方式,双战线打斗不断,着实很高能,很热血。可是不知不觉中,动画已经更新到了第12集,这也就
WOT丨人民币256元的8金重坦!一梭子2000血但大神也玩不来!本文首发于微信公众号坦克零距离,文章转载权限坦克空间站UP为个人专栏文章作者,非官方人员,在头条同步更新文章这是第一次直接卖蝰蛇各位车长老爷们大家好啊,我是阿纳贝尔丶卡多。本周国服小昆虫竟藏着国之重器的秘密看到航天员们的在轨日常时不知道大家会不会有这样的疑惑空间站外面可以自由伸缩的细长机械臂好像有点意思但空间站体积巨大它是如何做到可以围绕整个空间站来拍摄的呢近日,中国空间站系统总设计瞧,手机屏幕之外的风景云旅游云灯会云冰雕云拜年云祈福兔年春节,许多地方和媒介平台通过直播的方式展示春节文化场景,极大丰富了我们的休闲娱乐和精神生活。互联网信息技术为中国年带来了新气象。智能手机不断更新换陈道富提振预期和信心需要更好地发挥市场主体内在的活力和动力国务院发展研究中心金融所副所长陈道富3月19日,国务院发展研究中心金融所副所长陈道富在全球财富管理论坛2023年会上表示,今年应该更多关注需求不足的问题,扩大内需是一个政策重点,要中建一局先导(昆明)新材料科技产业园项目(薄膜材料)B1区首栋主体结构顺利封顶3月20日,云南省重点招商引资项目先导(昆明)新材料科技产业园项目按下快进键,跑出高质量发展加速度,薄膜材料B1区首栋主体结构顺利封顶,预计6月中旬完成区域内主体结构的全面封顶。首自主游戏,展现别样风景自主游戏,展现别样风景记江苏泰州兴化市学前教育课程改革孩子们一个接一个地登上跳台,模拟跳水运动员,从跳板上纵身一跃,欢呼着享受挑战的快乐。落地后,他们从软垫上弹起,抹了抹额头上的汗3月18日大老虎崔茂虎,调入中央九个月后,被审查调查据中央纪委国家监委网站3月18日消息,中央统战部原副部长,国家宗教事务局原局长崔茂虎接受中央纪委国家监委纪律审查和监察调查。图片源自网络,侵权必删崔茂虎是两会以来第二位落马副部级官一汽解放吉林化纤入选全国创建世界一流专精特新示范企业名单视频加载中日前,国务院国资委下发关于印发创建世界一流示范企业和专精特新示范企业名单的通知。全国200家企业入选创建世界一流专精特新示范企业名单,一汽解放汽车有限公司和吉林化纤集团有速看!大批高校公布复试线和复试名单!2023研考线下复试注意事项进入3月下旬,距离国家线公布已经10天了,34所自划线院校复试线已公布完毕,3月下旬大批非自划线院校扎堆公布复试线和复试名单注以下为不完全统计,请考生随时关注目标院校研究生院,院系马库斯富里乌斯卡米卢斯对罗马的贡献围攻维伊岛和重建罗马文字悠悠编辑悠悠前言罗马是一个出现在公元前8世纪的城邦,最终发展成为历史上最强大的帝国之一。然而,其早期历史的特点是与邻近的城邦部落和王国不断发生冲突。罗马历史的这一时期被称为罗马上午1130,央视新闻直播探访京西古街模式口,石景山融媒同步转播春游模式口2023年3月20日探访直播来啦京西古道模式口,悠悠驼铃数百年。模式口自古以来就是京都通往塞外的驼铃古道,是一个拥有深厚底蕴的历史文化街区,也是西山永定河文化带的重要节点