You Don't Need jQuery
前端發(fā)展很快,現(xiàn)代瀏覽器原生 API 已經(jīng)足夠好用。我們并不需要為了操作 DOM、Event 等再學(xué)習(xí)一下 jQuery 的 API。同時由于 React、Angular、Vue 等框架的流行,直接操作 DOM 不再是好的模式,jQuery 使用場景大大減少。本項目總結(jié)了大部分 jQuery API 替代的方法,暫時只支持 IE10 以上瀏覽器。
目錄
Translations
Query Selector
常用的 class、id、屬性 選擇器都可以使用document.querySelector或document.querySelectorAll替代。區(qū)別是
document.querySelector返回第一個匹配的 Element
document.querySelectorAll返回所有匹配的 Element 組成的 NodeList。它可以通過[].slice.call()把它轉(zhuǎn)成 Array
如果匹配不到任何 Element,jQuery 返回空數(shù)組[],但document.querySelector返回null,注意空指針異常。當(dāng)找不到時,也可以使用||設(shè)置默認(rèn)的值,如document.querySelectorAll(selector) || []
注意:document.querySelector和document.querySelectorAll性能很差。如果想提高性能,盡量使用document.getElementById、document.getElementsByClassName或document.getElementsByTagName。
1.0選擇器查詢
// jQuery$('selector');?// Nativedocument.querySelectorAll('selector');
1.1class 查詢
// jQuery$('.class');?// Nativedocument.querySelectorAll('.class');?// ordocument.getElementsByClassName('class');
1.2id 查詢
// jQuery$('#id');?// Nativedocument.querySelector('#id');?// ordocument.getElementById('id');
1.3屬性查詢
// jQuery$('a[target=_blank]');?// Nativedocument.querySelectorAll('a[target=_blank]');
1.4后代查詢
// jQuery$el.find('li');?// Nativeel.querySelectorAll('li');
1.5兄弟及上下元素
兄弟元素
// jQuery$el.siblings();?// Native - latest, Edge13+[...el.parentNode.children].filter((child)=>child!==el);// Native (alternative) - latest, Edge13+Array.from(el.parentNode.children).filter((child)=>child!==el);// Native - IE10+Array.prototype.filter.call(el.parentNode.children, (child)=>child!==el);
上一個元素
// jQuery$el.prev();?// Nativeel.previousElementSibling;
下一個元素
// next$el.next();?// Nativeel.nextElementSibling;
1.6Closest
Closest 獲得匹配選擇器的第一個祖先元素,從當(dāng)前元素開始沿 DOM 樹向上。
// jQuery$el.closest(queryString);?// Native - Only latest, NO IEel.closest(selector);?// Native - IE10+functionclosest(el,selector) {constmatchesSelector=el.matches||el.webkitMatchesSelector||el.mozMatchesSelector||el.msMatchesSelector;?while(el) {if(matchesSelector.call(el,selector)) {returnel;}else{el=el.parentElement;}}returnnull;}
1.7Parents Until
獲取當(dāng)前每一個匹配元素集的祖先,不包括匹配元素的本身。
// jQuery$el.parentsUntil(selector,filter);?// NativefunctionparentsUntil(el,selector,filter) {constresult=[];constmatchesSelector=el.matches||el.webkitMatchesSelector||el.mozMatchesSelector||el.msMatchesSelector;?// match start from parentel=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;}returnresult;}
1.8Form
Input/Textarea
// jQuery$('#my-input').val();?// Nativedocument.querySelector('#my-input').value;
獲取 e.currentTarget 在.radio中的數(shù)組索引
// jQuery$('.radio').index(e.currentTarget);?// NativeArray.prototype.indexOf.call(document.querySelectorAll('.radio'),e.currentTarget);
1.9Iframe Contents
jQuery 對象的 iframecontents()返回的是 iframe 內(nèi)的document
Iframe contents
// jQuery$iframe.contents();?// Nativeiframe.contentDocument;
Iframe Query
// jQuery$iframe.contents().find('.css');?// Nativeiframe.contentDocument.querySelectorAll('.css');
1.10獲取 body
// jQuery$('body');?// Nativedocument.body;
1.11獲取或設(shè)置屬性
獲取屬性
// jQuery$el.attr('foo');?// Nativeel.getAttribute('foo');
設(shè)置屬性
// jQuery, note that this works in memory without change the DOM$el.attr('foo','bar');?// Nativeel.setAttribute('foo','bar');
獲取data-屬性
// jQuery$el.data('foo');?// Native (use `getAttribute`)el.getAttribute('data-foo');?// Native (use `dataset` if only need to support IE 11+)el.dataset['foo'];
CSS & Style
2.1CSS
Get style
// jQuery$el.css("color");?// Native// 注意:此處為了解決當(dāng) style 值為 auto 時,返回 auto 的問題constwin=el.ownerDocument.defaultView;?// null 的意思是不返回偽類元素win.getComputedStyle(el,null).color;
Set style
// jQuery$el.css({color:"#ff0011"});?// Nativeel.style.color='#ff0011';
Get/Set Styles
注意,如果想一次設(shè)置多個 style,可以參考 oui-dom-utils 中setStyles方法
Add class
// jQuery$el.addClass(className);?// Nativeel.classList.add(className);
Remove class
// jQuery$el.removeClass(className);?// Nativeel.classList.remove(className);
has class
// jQuery$el.hasClass(className);?// Nativeel.classList.contains(className);
Toggle class
// jQuery$el.toggleClass(className);?// Nativeel.classList.toggle(className);
2.2Width & Height
Width 與 Height 獲取方法相同,下面以 Height 為例:
Window height
// window height$(window).height();?// 含 scrollbarwindow.document.documentElement.clientHeight;?// 不含 scrollbar,與 jQuery 行為一致window.innerHeight;
Document height
// jQuery$(document).height();?// Nativeconstbody=document.body;consthtml=document.documentElement;constheight=Math.max(body.offsetHeight,body.scrollHeight,html.clientHeight,html.offsetHeight,html.scrollHeight);
Element height
// jQuery$el.height();?// NativefunctiongetHeight(el) {conststyles=this.getComputedStyle(el);constheight=el.offsetHeight;constborderTopWidth=parseFloat(styles.borderTopWidth);constborderBottomWidth=parseFloat(styles.borderBottomWidth);constpaddingTop=parseFloat(styles.paddingTop);constpaddingBottom=parseFloat(styles.paddingBottom);returnheight-borderBottomWidth-borderTopWidth-paddingTop-paddingBottom;}?// 精確到整數(shù)(border-box 時為 height - border 值,content-box 時為 height + padding 值)el.clientHeight;?// 精確到小數(shù)(border-box 時為 height 值,content-box 時為 height + padding + border 值)el.getBoundingClientRect().height;
2.3Position & Offset
Position
獲得匹配元素相對父元素的偏移
// jQuery$el.position();?// Native{left:el.offsetLeft,top:el.offsetTop}
Offset
獲得匹配元素相對文檔的偏移
// jQuery$el.offset();?// NativefunctiongetOffset(el) {constbox=el.getBoundingClientRect();?return{top:box.top+window.pageYOffset-document.documentElement.clientTop,left:box.left+window.pageXOffset-document.documentElement.clientLeft}}
2.4Scroll Top
獲取元素滾動條垂直位置。
// jQuery$(window).scrollTop();?// Native(document.documentElement&&document.documentElement.scrollTop)||document.body.scrollTop;
DOM Manipulation
3.1Remove
從 DOM 中移除元素。
// jQuery$el.remove();?// Nativeel.parentNode.removeChild(el);
3.2Text
Get text
返回指定元素及其后代的文本內(nèi)容。
// jQuery$el.text();?// Nativeel.textContent;
Set text
設(shè)置元素的文本內(nèi)容。
// jQuery$el.text(string);?// Nativeel.textContent=string;
3.3HTML
Get HTML
// jQuery$el.html();?// Nativeel.innerHTML;
Set HTML
// jQuery$el.html(htmlString);?// Nativeel.innerHTML=htmlString;
3.4Append
Append 插入到子節(jié)點(diǎn)的末尾
// jQuery$el.append("
3.5Prepend
// jQuery$el.prepend("
3.6insertBefore
在選中元素前插入新節(jié)點(diǎn)
// jQuery$newEl.insertBefore(queryString);?// Native (HTML string)el.insertAdjacentHTML('beforebegin ','
3.7insertAfter
在選中元素后插入新節(jié)點(diǎn)
// jQuery$newEl.insertAfter(queryString);?// Native (HTML string)el.insertAdjacentHTML('afterend','
3.8is
如果匹配給定的選擇器,返回true
// jQuery$el.is(selector);?// Nativeel.matches(selector);
3.9clone
深拷貝被選元素。(生成被選元素的副本,包含子節(jié)點(diǎn)、文本和屬性。)
//jQuery$el.clone();?//Nativeel.cloneNode();
//深拷貝添加參數(shù)‘true’```
3.10empty
移除所有子節(jié)點(diǎn)
//jQuery$el.empty();?//Nativeel.innerHTML='';
3.11wrap
把每個被選元素放置在指定的HTML結(jié)構(gòu)中。
//jQuery$(".inner").wrap('
');?//NativeArray.prototype.forEach.call(document.querySelector('.inner'), (el)=>{constwrapper=document.createElement('div');wrapper.className='wrapper';el.parentNode.insertBefore(wrapper,el);el.parentNode.removeChild(el);wrapper.appendChild(el);});3.12unwrap
把被選元素的父元素移除DOM結(jié)構(gòu)
// jQuery$('.inner').unwrap();?// NativeArray.prototype.forEach.call(document.querySelectorAll('.inner'), (el)=>{Array.prototype.forEach.call(el.childNodes, (child)=>{el.parentNode.insertBefore(child,el);});el.parentNode.removeChild(el);});
3.13replaceWith
用指定的元素替換被選的元素
//jQuery$('.inner').replaceWith('
');?//NativeArray.prototype.forEach.call(document.querySelectorAll('.inner'),(el)=>{constouter=document.createElement("div");outer.className="outer";el.parentNode.insertBefore(outer,el);el.parentNode.removeChild(el);});3.14simple parse
解析 HTML/SVG/XML 字符串
// jQuery$(`
- a
- b
- c
- d
- a
- b
- c
- d
Ajax
Fetch API是用于替換 XMLHttpRequest 處理 ajax 的新標(biāo)準(zhǔn),Chrome 和 Firefox 均支持,舊瀏覽器可以使用 polyfills 提供支持。
IE9+ 請使用github/fetch,IE8+ 請使用fetch-ie8,JSONP 請使用fetch-jsonp。
4.1從服務(wù)器讀取數(shù)據(jù)并替換匹配元素的內(nèi)容。
// jQuery$(selector).load(url,completeCallback)?// Nativefetch(url).then(data=>data.text()).then(data=>{document.querySelector(selector).innerHTML=data}).then(completeCallback)
Events
完整地替代命名空間和事件代理,鏈接到https://github.com/oneuijs/oui-dom-events
5.0Document ready byDOMContentLoaded
// jQuery$(document).ready(eventHandler);?// Native// 檢測 DOMContentLoaded 是否已完成if(document.readyState==='complete'||document.readyState!=='loading') {eventHandler();}else{document.addEventListener('DOMContentLoaded',eventHandler);}
5.1使用 on 綁定事件
// jQuery$el.on(eventName,eventHandler);?// Nativeel.addEventListener(eventName,eventHandler);
5.2使用 off 解綁事件
// jQuery$el.off(eventName,eventHandler);?// Nativeel.removeEventListener(eventName,eventHandler);
5.3Trigger
// jQuery$(el).trigger('custom-event', {key1:'data'});?// Nativeif(window.CustomEvent) {constevent=newCustomEvent('custom-event', {detail: {key1:'data'}});}else{constevent=document.createEvent('CustomEvent');event.initCustomEvent('custom-event',true,true, {key1:'data'});}?el.dispatchEvent(event);
Utilities
大部分實用工具都能在 native API 中找到. 其他高級功能可以選用專注于該領(lǐng)域的穩(wěn)定性和性能都更好的庫來代替,推薦lodash。
6.1基本工具
isArray
檢測參數(shù)是不是數(shù)組。
// jQuery$.isArray(range);?// NativeArray.isArray(range);
isWindow
檢測參數(shù)是不是 window。
// jQuery$.isWindow(obj);?// NativefunctionisWindow(obj) {returnobj!==null&&obj!==undefined&&obj===obj.window;}
inArray
在數(shù)組中搜索指定值并返回索引 (找不到則返回 -1)。
// jQuery$.inArray(item,array);?// Nativearray.indexOf(item)>-1;?// ES6-wayarray.includes(item);
isNumeric
檢測傳入的參數(shù)是不是數(shù)字。Usetypeofto decide the type or thetypeexample for better accuracy.
// jQuery$.isNumeric(item);?// NativefunctionisNumeric(value) {vartype=typeofvalue;?return(type==='number'||type==='string')&&!Number.isNaN(value-Number.parseFloat(value));}
isFunction
檢測傳入的參數(shù)是不是 JavaScript 函數(shù)對象。
// jQuery$.isFunction(item);?// NativefunctionisFunction(item) {if(typeofitem==='function') {returntrue;}vartype=Object.prototype.toString(item);returntype==='[object Function]'||type==='[object GeneratorFunction]';}
isEmptyObject
檢測對象是否為空 (包括不可枚舉屬性).
// jQuery$.isEmptyObject(obj);?// NativefunctionisEmptyObject(obj) {returnObject.keys(obj).length===0;}
isPlainObject
檢測是不是扁平對象 (使用 “{}” 或 “new Object” 創(chuàng)建).
// jQuery$.isPlainObject(obj);?// NativefunctionisPlainObject(obj) {if(typeof(obj)!=='object'||obj.nodeType||obj!==null&&obj!==undefined&&obj===obj.window) {returnfalse;}?if(obj.constructor&&!Object.prototype.hasOwnProperty.call(obj.constructor.prototype,'isPrototypeOf')) {returnfalse;}?returntrue;}
extend
合并多個對象的內(nèi)容到第一個對象。object.assign 是 ES6 API,也可以使用polyfill。
// jQuery$.extend({},defaultOpts,opts);?// NativeObject.assign({},defaultOpts,opts);
trim
移除字符串頭尾空白。
// jQuery$.trim(string);?// Nativestring.trim();
map
將數(shù)組或?qū)ο筠D(zhuǎn)化為包含新內(nèi)容的數(shù)組。
// jQuery$.map(array, (value,index)=>{});?// Nativearray.map((value,index)=>{});
each
輪詢函數(shù),可用于平滑的輪詢對象和數(shù)組。
// jQuery$.each(array, (index,value)=>{});?// Nativearray.forEach((value,index)=>{});
grep
找到數(shù)組中符合過濾函數(shù)的元素。
// jQuery$.grep(array, (value,index)=>{});?// Nativearray.filter((value,index)=>{});
type
檢測對象的 JavaScript [Class] 內(nèi)部類型。
// jQuery$.type(obj);?// Nativefunctiontype(item) {constreTypeOf=/(?:^\[object\s(.*?)\]$)/;returnObject.prototype.toString.call(item).replace(reTypeOf,'$1').toLowerCase();}
merge
合并第二個數(shù)組內(nèi)容到第一個數(shù)組。
// jQuery$.merge(array1,array2);?// Native// But concat function doesn't remove duplicate items.functionmerge(...args) {return[].concat(...args)}
now
返回當(dāng)前時間的數(shù)字呈現(xiàn)。
// jQuery$.now();?// NativeDate.now();
proxy
傳入函數(shù)并返回一個新函數(shù),該函數(shù)綁定指定上下文。
// jQuery$.proxy(fn,context);?// Nativefn.bind(context);
makeArray
類數(shù)組對象轉(zhuǎn)化為真正的 JavaScript 數(shù)組。
// jQuery$.makeArray(arrayLike);?// NativeArray.prototype.slice.call(arrayLike);?// ES6-wayArray.from(arrayLike);
6.2包含
檢測 DOM 元素是不是其他 DOM 元素的后代.
// jQuery$.contains(el,child);?// Nativeel!==child&&el.contains(child);
6.3Globaleval
全局執(zhí)行 JavaScript 代碼。
// jQuery$.globaleval(code);?// NativefunctionGlobaleval(code) {constscript=document.createElement('script');script.text=code;?document.head.appendChild(script).parentNode.removeChild(script);}?// Use eval, but context of eval is current, context of $.Globaleval is global.eval(code);
6.4解析
parseHTML
解析字符串為 DOM 節(jié)點(diǎn)數(shù)組.
// jQuery$.parseHTML(htmlString);?// NativefunctionparseHTML(string) {constcontext=document.implementation.createHTMLDocument();?// Set the base href for the created document so any parsed elements with URLs// are based on the document's URLconstbase=context.createElement('base');base.href=document.location.href;context.head.appendChild(base);?context.body.innerHTML=string;returncontext.body.children;}
parseJSON
傳入格式正確的 JSON 字符串并返回 JavaScript 值.
// jQuery$.parseJSON(str);?// NativeJSON.parse(str);
Promises
Promise 代表異步操作的最終結(jié)果。jQuery 用它自己的方式處理 promises,原生 JavaScript 遵循Promises/A+標(biāo)準(zhǔn)實現(xiàn)了最小 API 來處理 promises。
7.1done, fail, always
done會在 promise 解決時調(diào)用,fail會在 promise 拒絕時調(diào)用,always總會調(diào)用。
// jQuery$promise.done(doneCallback).fail(failCallback).always(alwaysCallback)?// Nativepromise.then(doneCallback,failCallback).then(alwaysCallback,alwaysCallback)
7.2when
when用于處理多個 promises。當(dāng)全部 promises 被解決時返回,當(dāng)任一 promise 被拒絕時拒絕。
// jQuery$.when($promise1,$promise2).done((promise1Result,promise2Result)=>{});?// NativePromise.all([$promise1,$promise2]).then([promise1Result,promise2Result]=>{});
7.3Deferred
Deferred 是創(chuàng)建 promises 的一種方式。
// jQueryfunctionasyncFunc() {constdefer=new$.Deferred();setTimeout(()=>{if(true) {defer.resolve('some_value_computed_asynchronously');}else{defer.reject('failed');}},1000);?returndefer.promise();}?// NativefunctionasyncFunc() {returnnewPromise((resolve,reject)=>{setTimeout(()=>{if(true) {resolve('some_value_computed_asynchronously');}else{reject('failed');}},1000);});}?// Deferred wayfunctiondefer() {constdeferred={};constpromise=newPromise((resolve,reject)=>{deferred.resolve=resolve;deferred.reject=reject;});?deferred.promise=()=>{returnpromise;};?returndeferred;}?functionasyncFunc() {constdefer=defer();setTimeout(()=>{if(true) {defer.resolve('some_value_computed_asynchronously');}else{defer.reject('failed');}},1000);?returndefer.promise();}
Animation
8.1Show & Hide
// jQuery$el.show();$el.hide();?// Native// 更多 show 方法的細(xì)節(jié)詳見 https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L363el.style.display=''|'inline'|'inline-block'|'inline-table'|'block';el.style.display='none';
8.2Toggle
顯示或隱藏元素。
// jQuery$el.toggle();?// Nativeif(el.ownerDocument.defaultView.getComputedStyle(el,null).display==='none') {el.style.display=''|'inline'|'inline-block'|'inline-table'|'block';}else{el.style.display='none';}
8.3FadeIn & FadeOut
// jQuery$el.fadeIn(3000);$el.fadeOut(3000);?// Nativeel.style.transition='opacity 3s';// fadeInel.style.opacity='1';// fadeOutel.style.opacity='0';
8.4FadeTo
調(diào)整元素透明度。
// jQuery$el.fadeTo('slow',0.15);// Nativeel.style.transition='opacity 3s';// 假設(shè) 'slow' 等于 3 秒el.style.opacity='0.15';
8.5FadeToggle
動畫調(diào)整透明度用來顯示或隱藏。
// jQuery$el.fadeToggle();?// Nativeel.style.transition='opacity 3s';const{opacity}=el.ownerDocument.defaultView.getComputedStyle(el,null);if(opacity==='1') {el.style.opacity='0';}else{el.style.opacity='1';}
8.6SlideUp & SlideDown
// jQuery$el.slideUp();$el.slideDown();?// NativeconstoriginHeight='100px';el.style.transition='height 3s';// slideUpel.style.height='0px';// slideDownel.style.height=originHeight;
8.7SlideToggle
滑動切換顯示或隱藏。
// jQuery$el.slideToggle();?// NativeconstoriginHeight='100px';el.style.transition='height 3s';const{height}=el.ownerDocument.defaultView.getComputedStyle(el,null);if(parseInt(height,10)===0) {el.style.height=originHeight;}else{el.style.height='0px';}
8.8Animate
執(zhí)行一系列 CSS 屬性動畫。
// jQuery$el.animate({params},speed);?// Nativeel.style.transition='all '+speed;Object.keys(params).forEach((key)=>el.style[key]=params[key];)
Alternatives
你可能不需要 jQuery (You Might Not Need jQuery)- 如何使用原生 JavaScript 實現(xiàn)通用事件,元素,ajax 等用法。
npm-dom以及webmodules- 在 NPM 上提供獨(dú)立 DOM 模塊的組織
Browser Support
Latest ?Latest ?10+ ?Latest ?6.1+ ?
License
MIT
chrome-imagehttps://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png
firefox-imagehttps://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png
ie-imagehttps://raw.github.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png
opera-imagehttps://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png
safari-imagehttps://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png