這是一篇使用原生JavaScript代替jQuery實踐的文章, GitHub 原文
前端發展很快,現代瀏覽器原生 API 已經足夠好用。我們並不需要爲了操作 DOM、Event 等再學習一下 jQuery 的 API。同時由於 React、Angular、Vue
等框架的流行,直接操作 DOM 不再是好的模式,jQuery 使用場景大大減少。本項目總結了大部分 jQuery API 替代的方法,暫時只支持 IE10+ 以上瀏覽器。
1.Query Selector
常用的 class、id、屬性 選擇器都可以使用 document.querySelector或 document.querySelectorAll
替代。區別是
document.querySelector 返回第一個匹配的 Element
document.querySelectorAll
返回所有匹配的 Element 組成的 NodeList。它可以通過 [].slice.call() 把它轉成 Array
如果匹配不到任何 Element,jQuery 返回空數組 [],但 document.querySelector返回 nul ,注意空指針異常。當找不到時,
也可以使用 ||設置默認的值,如 document.querySelectorAll(selector) || []
注意: document.querySelector
和 document.querySelectorAll
性能很差。如果想提高性能,儘量使用
document.getElementById
、document.getElementsByClassName
或 document.getElementsByTagName
。
// jQuery
$('selector');
// Native
document.querySelectorAll('selector');
// jQuery
$('.css');
// Native
document.querySelectorAll('.css');
// or
document.getElementsByClassName('css');
// jQuery
$('#id');
// Native
document.querySelector('#id');
// or
document.getElementById('id');
// jQuery
$('a[target=_blank]');
// Native
document.querySelectorAll('a[target=_blank]');
1.4 Find sth.
Find nodes
// jQuery
$el.find('li');
// Native
el.querySelectorAll('li');
Find body
// jQuery
$('body');
// Native
document.body;
Find Attribute
// jQuery
$el.attr('foo');
// Native
e.getAttribute('foo');
Find data attribute
// jQuery
$el.data('foo');
// Native
// using getAttribute
el.getAttribute('data-foo');
// you can also use `dataset` if only need to support IE 11+
el.dataset['foo'];
1.5 Sibling/Previous/Next Elements
Sibling elements
// jQuery
$el.siblings();
// Native
[].filter.call(el.parentNode.children, function(child)
{ return child !== el;});
Previous elements
// jQuery
$el.prev();
// Native
el.previousElementSibling;
Next elements
// next
$el.next();
el.nextElementSibling;
1.6 Closest
Closest 獲得匹配選擇器的第一個祖先元素,從當前元素開始沿 DOM 樹向上。
// jQuery
$el.closest(queryString);
// Native
function closest(el, selector)
{ const matchesSelector = el.matches || el.webkitMatchesSelector
|| el.mozMatchesSelector || el.msMatchesSelector;
while (el)
{
if (matchesSelector.call(el, selector))
{ return el; }
else
{ el = el.parentElement; } }
return null;
}
1.7 Parents Until
獲取當前每一個匹配元素集的祖先,不包括匹配元素的本身。
// jQuery
$el.parentsUntil(selector, filter);
// Native
function parentsUntil(el, selector, filter)
{ const result = []; const matchesSelector = el.matches ||
el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
// match start from parent
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;
}
1.8 Form
Input/Textarea
// jQuery
$('#my-input').val();
// Native
document.querySelector('#my-input').value;
Get index of e.currentTarget between .radio
// jQuery
$(e.currentTarget).index('.radio');
// Native
[].indexOf.call(document.querySelectorAll('.radio'), e.currentTarget);
jQuery 對象的 iframe contents() 返回的是 iframe 內的 document
Iframe contents
// jQuery
$iframe.contents();
// Native
iframe.contentDocument;
Iframe Query
// jQuery
$iframe.contents().find('.css');
// Native
iframe.contentDocument.querySelectorAll('.css');
CSS & Style
// jQuery
$el.css("color");
// Native
// 注意:此處爲了解決當 style 值爲 auto 時,返回 auto 的問題
const win = el.ownerDocument.defaultView;
// null 的意思是不返回僞類元素
win.getComputedStyle(el, null).color;
Set style
““
// jQuery
$el.css({ color: “#ff0011” });
// Native
el.style.color = ‘#ff0011’;
Get/Set Styles
注意,如果想一次設置多個 style,可以參考 oui-dom-utils 中 [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) 方法
Add class
// jQuery
$el.addClass(className);
// Native
el.classList.add(className);
Remove class
// jQuery
$el.removeClass(className);
// Native
el.classList.remove(className);
has class
// jQuery
$el.hasClass(className);
// Native
el.classList.contains(className);
Toggle class
// jQuery
$el.toggleClass(className);
// Native
el.classList.toggle(className);
[2.2 Width & Height](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#2.2)
Width 與 Height 獲取方法相同,下面以 Height 爲例:
Window height
// jQuery
$(window).height();
// Native
// 不含 scrollbar,與 jQuery 行爲一致
window.document.documentElement.clientHeight;
// 含
scrollbarwindow.innerHeight;
Document height
// jQuery
$(document).height();
// Native
document.documentElement.scrollHeight;
Element height
// jQuery
$el.height();
// Native// 與 jQuery 一致(一直爲 content 區域的高度)
function getHeight(el)
{
const styles = this.getComputedStyles(el);
const height = el.offsetHeight;
const borderTopWidth = parseFloat(styles.borderTopWidth);
const borderBottomWidth = parseFloat(styles.borderBottomWidth);
const paddingTop = parseFloat(styles.paddingTop);
const paddingBottom = parseFloat(styles.paddingBottom);
return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom;
}
// 精確到整數(border-box 時爲 height 值,content-box 時爲 height + padding + border 值)el.clientHeight;
// 精確到小數(border-box 時爲 height 值,content-box 時爲 height + padding + border 值)el.getBoundingClientRect().height;
Iframe height
// Native
iframe.contentDocument.documentElement.scrollHeight;
[2.3 Position & Offset](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#2.3)
Position
// jQuery
$el.position();
// Native
{ left: el.offsetLeft, top: el.offsetTop }
Offset
// jQuery
$el.offset();
// Native
function getOffset (el)
{
const box = el.getBoundingClientRect();
return { top: box.top + window.pageYOffset - document.documentElement.clientTop,
left: box.left + window.pageXOffset - document.documentElement.clientLeft
}}
[2.4 Scroll Top](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#2.4)
// jQuery
$(window).scrollTop();
// Native
(document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
#DOM Manipulation
[3.1 Remove](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.1)
// jQuery
$el.remove();
// Native
el.parentNode.removeChild(el);
[3.2 Text Get text](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.2)
// jQuery
$el.text();
// Native
el.textContent;
Set text
// jQuery
$el.text(string);
// Native
el.textContent = string;
[3.3 HTML](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.3)
Get HTML
// jQuery
$el.html();
// Native
el.innerHTML;
Set HTML
// jQuery
$el.html(htmlString);
// Native
el.innerHTML = htmlString;
[3.4 Append](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.4)
Append 插入到子節點的末尾
// jQuery
$el.append(“
// Native
let newEl = document.createElement(‘div’);
newEl.setAttribute(‘id’, ‘container’);
newEl.innerHTML = ‘hello’;el.appendChild(newEl);
[3.5 Prepend](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.5)
// jQuery
$el.prepend(“
// Native
let newEl = document.createElement(‘div’);
newEl.setAttribute(‘id’, ‘container’);
newEl.innerHTML = ‘hello’;
el.insertBefore(newEl, el.firstChild);
[3.6 insertBefore](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.6)
在選中元素前插入新節點
// jQuery
$newEl.insertBefore(queryString);
// Native
const target = document.querySelector(queryString);
target.parentNode.insertBefore(newEl, target);
[3.7 insertAfter](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#3.7)
在選中元素後插入新節點
// jQuery
$newEl.insertAfter(queryString);
// Native
const target = document.querySelector(queryString);
target.parentNode.insertBefore(newEl, target.nextSibling);
Ajax
用 [fetch](https://github.com/camsong/fetch-ie8) 和 [fetch-jsonp](https://github.com/camsong/fetch-jsonp) 替代
Events
完整地替代命名空間和事件代理,鏈接到 [https://github.com/oneuijs/oui-dom-events](https://github.com/oneuijs/oui-dom-events)
[5.1 Bind an event with on](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#5.1)
// jQuery
$el.on(eventName, eventHandler);
// Native
el.addEventListener(eventName, eventHandler);
[5.2 Unbind an event with off](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#5.2)
// jQuery
$el.off(eventName, eventHandler);
// Native
el.removeEventListener(eventName, eventHandler);
[5.3 Trigger](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#5.3)
// jQuery
$(el).trigger(‘custom-event’, {key1: ‘data’});
// Native
if (window.CustomEvent) { const event = new CustomEvent(‘custom-event’,
{detail: {key1: ‘data’}});}
else { const event = document.createEvent(‘CustomEvent’);
event.initCustomEvent(‘custom-event’, true, true, {key1: ‘data’});
}
el.dispatchEvent(event);
#Utilities
[6.1 isArray](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#6.1)
// jQuery
$.isArray(range);
// Native
Array.isArray(range);
[6.2 Trim](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#6.2)
// jQuery
$.trim(string);
// Native
string.trim();
[6.3 Object Assign](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#6.3)
繼承,使用 object.assign polyfill [https://github.com/ljharb/object.assign](https://github.com/ljharb/object.assign)
// jQuery
$.extend({}, defaultOpts, opts);
// Native
Object.assign({}, defaultOpts, opts);
[6.4 Contains](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md#6.4)
// jQuery
$.contains(el, child);
// Native
el !== child && el.contains(child);
“`
Alternatives
你可能不需要 jQuery (You Might Not Need jQuery) - 如何使用原生 JavaScript 實現通用事件,元素,ajax 等用法。
npm-dom 以及 webmodules - 在 NPM 上提供獨立 DOM 模塊的組織