大家好,很高兴又见面了,我是"前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
今天在逛Github时无意间发现一个仓库《You Dont Need jQuery》。打开来看,发现很有意思!而且作者列举了很多jQuery常用的方法以及原生实现,因此这篇文章将以此展开。话不多说,直接开始!
关于更多jQuery的讨论可以阅读文末我的另一篇文章《18岁了!老伙计jQuery过的怎样?》
前端发展迅速,现代浏览器已经实现了大量足以用于生产的 DOM/BOM API。 不必从头开始学习 jQuery 来进行 DOM 操作或其他类型事件处理。 与此同时,由于 React、Angular 和 Vue 等前端库的普及,直接操作 DOM 并非最好的方法。 该项目总结了 jQuery 方法的原生 Javascript 替代方法,并支持 IE 10+。
ℹ️ 注意:
可以使用 document.querySelector 或 document.querySelectorAll 代替常见的jQuery选择器,如 class、id 或 attribute。 不同之处在于:
注意: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;
}
// jQuery
$el.css('color');
// 原生替代方法
// 注意: 已知错误,如果样式值为“auto”,将返回“auto”
const win = el.ownerDocument.defaultView;
// null 表示不返回伪样式
win.getComputedStyle(el, null).color;
// 原生替代方法
el.style.color = '#f01';
// jQuery
$el.addClass(className);
// 原生替代方法
el.classList.add(className);
// 添加class
el.classList.remove(className);
// 移除class
el.classList.contains(className);
// 包含class
el.classList.toggle(className);
// toggle class
// 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
};
}
// jQuery
$(window).scrollTop();
// 原生替代方法
(document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
// jQuery
$el.remove();
// 原生替代方法
el.parentNode.removeChild(el);
// jQuery
$el.html();
// 原生替代方法
el.innerHTML;
// jQuery设置html
$el.html(htmlString);
// 原生替代方法设置html
el.innerHTML = htmlString;
// jQuery:DOMString 和 Node 对象的统一语法
$parent.append(newEl | 'Hello World');
// 原生方法:不同语法
parent.insertAdjacentHTML('beforeend', 'Hello World');
parent.appendChild(newEl);
// Native (ES6-way):统一语法
parent.append(newEl | 'Hello World');
// 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');
// jQuery
$newEl.insertBefore(selector);
// 原生方法
el.insertAdjacentHTML('beforebegin ', 'Hello World');
// 原生 (元素)
const el = document.querySelector(selector);
if (el.parentNode) {
// 父元素的insertBefore
el.parentNode.insertBefore(newEl, el);
}
// 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);
}
// 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);
});
// 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);
});
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)
});
// 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);
// 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);
Promise 表示异步操作的最终结果。 jQuery 有自己的方式来处理Promise。本机 JavaScript 实现了一个精简的最小 API 来根据 Promises/A+ 规范处理 promises。
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 用于处理多个promise。当所有promise都resolve时,它将resolve,如果任何一个被拒绝,它就会拒绝。
// jQuery
$.when($promise1, $promise2).done((promise1Result, promise2Result) => {
});
// when原生替代方法
Promise.all([$promise1, $promise2]).then([promise1Result, promise2Result] => {});
是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();
}
// 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';
// 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';
}
// 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;
}
}
// jQuery
$el.slideUp();
$el.slideDown();
// 原生替代方法
const originHeight = '100px';
el.style.transition = 'height 3s';
// 原生替代方法:slideUp
el.style.height = '0px';
// 原生替代方法:slideDown
el.style.height = originHeight;
本文主要和大家介绍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》!
页面更新:2024-04-27
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号