在我看來,jQuery確實已通過時了。本項目總結了絕大部分 jQuery API 替代的方法,相似項目You-Dont-Need-jQuery,並會再此基礎上進行不少的補充。寫這個項目主要想讓本身和你們增進對javascript原生api的理解,也能夠做爲一個"原生jquery"的api文檔隨時查看。兼容ie9及以上瀏覽器,如不支持ie9會特別說明。javascript
原文地址 https://github.com/fa-ge/jQuery-is-out-of-datecss
Regulationhtml
DOM Manipulationjava
Query Selectornode
Ajaxjquery
Eventsgit
Utilitiesgithub
Animationweb
function $(selector) { return document.querySelector(selector) } function $$(selector) { return Array.prototype.slice.call(document.querySelectorAll(selector)) }
若是在jQuery示例下的$是jquery對象,在Native示例下的$是以上的實現。至關於實現了chrome控制檯上$,$$方法。chrome
不少人一直認爲jQuery尚未過期的其中一個緣由是在DOM操做上很是方便。接下來比較一下。
添加元素到匹配的元素集合。
// jQuery $(selector).add($(newEl)) // Native $$(selector).push(newEl)
爲每一個匹配的元素添加指定的樣式類名
// jQuery $(el).addClass(className) // Native (IE 10+ support) el.classList.add(className)
在匹配元素集合中的每一個元素後面插入參數所指定的內容,做爲其兄弟節點。
// jQuery $(el).after('<p></p>') // Native (Html string) el.insertAdjacentHTML('afterend', '<p></p>') // Native (Element) el.insertAdjacentElement('afterend', newEl) // Native (Element) el.parentNode.insertBefore(newEl, el.nextSibling)
在每一個匹配元素裏面的末尾處插入參數內容。
// jQuery $(el).append('<p></p>') // Native (Html string) el.insertAdjacentHTML('beforeend', '<p></p>') // Native (Element) el.insertAdjacentElement('beforeend', newEl) // Native (Element) el.appendChild(newEl)
與append相反
獲取匹配的元素集合中的第一個元素的屬性的值。設置每個匹配元素的一個或多個屬性。
// jQuery $(el).attr('foo') // Native el.getAttribute('foo') // jQuery $(el).attr('foo', 'bar') // Native el.setAttribute('foo', 'bar')
根據參數設定,在匹配元素的前面插入內容(外部插入)
// jQuery $(el).before('<p></p>') // Native (Html string) el.insertAdjacentHTML('beforebegin', '<p></p>') // Native (Element) el.insertAdjacentElement('beforebegin', newEl) // Native (Element) el.parentNode.insertBefore(newEl, el)
得到匹配元素集合中每一個元素的子元素,選擇器選擇性篩選。
// jQuery $(el).children() // Native el.children
建立一個匹配的元素集合的深度拷貝副本。
// jQuery $(el).clone() // Native el.cloneNode() // For Deep clone , set param as `true`
從元素自己開始,在DOM 樹上逐級向上級元素匹配,並返回最早匹配的祖先元素。以數組的形式返回與選擇器相匹配的全部元素,從當前元素開始,在 DOM 樹中向上遍歷。
// jQuery $el.closest(selector) // Native - Only latest, NO IE el.closest(selector) // Native function closest(el, selector = false) { const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector do { if (matchesSelector.call(el, selector)) { return el } } while ((el = el.parentElement) !== null) return null }
得到匹配元素集合中每一個元素的子元素,包括文字和註釋節點。
// jQuery $(el).contents() // Native el.childNodes
獲取匹配元素集合中的第一個元素的樣式屬性的值設置每一個匹配元素的一個或多個CSS屬性。
// jQuery $(el).css('color') // Native // 注意:此處爲了解決當 style 值爲 auto 時,返回 auto 的問題 const win = el.ownerDocument.defaultView // null 的意思是不返回僞類元素 win.getComputedStyle(el, null).color // jQuery $(el).css({ color: '#f01' }) // Native el.style.color = '#f01' // 一次性設置多個樣式 // jQuery $(el).css({ color: '#f01', 'background-color': '#000' }) // Native const cssObj = {color: '#f01', backgroundColor: '#000'} for (let key in cssObj) { el.style[key] = cssObj[key] } // Native const cssText = 'color: #f01; background-color: #000' el.style.cssText += cssText
從DOM中移除集合中匹配元素的全部子節點。
// jQuery $(el).empty() // Native el.innerHTML = ''
篩選元素集合中匹配表達式 或 經過傳遞函數測試的 那些元素集合。
// jQuery $(selector).filter(filterFn) // Native $$(selector).filter(filterFn)
經過一個選擇器,jQuery對象,或元素過濾,獲得當前匹配的元素集合中每一個元素的後代。
// jQuery $(el).find(selector) // Native el.querySelectorAll(selector)
篩選匹配元素集合中的那些有相匹配的選擇器或DOM元素的後代元素。
// jQuery $(selector).has('p') // Native $$(selector).filter(el => el.querySelector('p') !== null)
肯定任何一個匹配元素是否有被分配給定的(樣式)類。
// jQuery $(el).hasClass(className) // Native (IE 10+ support) el.classList.contains(className)
獲取匹配元素集合中的第一個元素的當前計算高度值。設置每個匹配元素的高度值。
// jQuery window $(window).height() // Native window.innerHeight // jQuery document $(document).height() // Native const body = document.body const html = document.documentElement const height = Math.max( body.offsetHeight, body.scrollHeight, html.clientHeight, html.offsetHeight, html.scrollHeight ) // jQuery Element (it's `height` always equals to content height) $(el).height() // Native function getHeight(el) { const styles = window.getComputedStyle(el) const height = el.clientHeight const paddingTop = parseFloat(styles.paddingTop) const paddingBottom = parseFloat(styles.paddingBottom) return height - paddingTop - paddingBottom } // Native // when `border-box`, it's `height` === (content height) + padding + border; when `content-box`, it's `height` === (content height) getComputedStyle(el, null).height
獲取集合中第一個匹配元素的HTML內容 設置每個匹配元素的html內容。
// jQuery $(el).html() // Native el.innerHTML // jQuery $(el).html(htmlString) // Native el.innerHTML = htmlString
爲匹配的元素集合中獲取第一個元素的當前計算高度值,包括padding,可是不包括border。
// jQuery $(el).innerHeight() // Native el.clientHeight()
爲匹配的元素集合中獲取第一個元素的當前計算寬度值,包括padding,可是不包括border。
// jQuery $(el).innerWidth() // Native el.clientWidth()
與after相反
與before相反
判斷當前匹配的元素集合中的元素,是否爲一個選擇器,DOM元素,或者jQuery對象,若是這些元素至少一個匹配給定的參數,那麼返回true。
// jQuery $(el).is(selector) // Native (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector)
取得匹配的元素集合中每個元素緊鄰的後面同輩元素的元素集合。若是提供一個選擇器,那麼只有緊跟着的兄弟元素知足選擇器時,纔會返回此元素。
// jQuery $(el).next() // Native el.nextElementSibling
得到每一個匹配元素集合中全部下面的同輩元素,選擇性篩選的選擇器。
// jQuery $(el).nextAll() // Native const nextAll = [] while((el = el.nextElementSibling) !== null) { nextAll.push(el) }
從匹配的元素集合中移除指定的元素。
// jQuery $(selector).not(matches) // Native const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector $$(selector).filter(el => !matchesSelector.call(el, matches))
在匹配的元素集合中,獲取的第一個元素的當前座標,座標相對於文檔。 設置匹配的元素集合中每個元素的座標, 座標相對於文檔。
// jQuery $(el).offset() // Native const elClientRect = el.getBoundingClientRect() { top: elClientRect.top + window.pageYOffset - document.documentElement.clientTop, left: elClientRect.left + window.pageXOffset - document.documentElement.clientLeft } // jQuery $(el).offset(10, 10) // Native const elClientRect = el.getBoundingClientRect() const elTop = 10 - elClientRect.top - document.documentElement.clientTop const elLeft = 10 - elClientRect.left - document.documentElement.clientLeft el.style.cssText += `position: relative;top: ${elTop}px;left: ${elLeft}px;`
// jQuery $(el).offsetParent() // Native el.offsetParent || el
獲取元素集合中第一個元素的當前計算高度值,包括padding,border和選擇性的margin。返回一個整數(不包含「px」)表示的值 ,或若是在一個空集合上調用該方法,則會返回 null。
// jQuery $(el).outerHeight() // Native el.offsetHeight // jQuery $(el).outerHeight(true) // Native const win = el.ownerDocument.defaultView const {marginTop, margintBottom} = win.getComputedStyle(el, null) el.offsetHeight + parseFloat(marginTop) + parseFloat(margintBottom) === $(el).outerHeight(true) // true
與outerHeight相似。
取得匹配元素集合中,每一個元素的父元素,能夠提供一個可選的選擇器。
// jQuery $(el).parent() // Native el.parentNode
得到集合中每一個匹配元素的祖先元素,能夠提供一個可選的選擇器做爲參數。
// jQuery $(el).parents(selector) // Native function parents(el, selector = '*') { const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector const parentsMatch = [] while ((el = el.parentElement) !== null) { if (matchesSelector.call(el, selector)) { parentsMatch.push(el) } } return parentsMatch }
查找當前元素的全部的前輩元素,直到遇到選擇器, DOM 節點或 jQuery 對象匹配的元素爲止,但不包括這些元素。
// jQuery $(el).parentsUntil(selector) // Native function parentsUntil(el, selector = false) { const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector const parentsMatch = [] while ((el = el.parentElement) !== null && !matchesSelector.call(el, selector)) { parentsMatch.push(el) } return parentsMatch }
獲取匹配元素中第一個元素的當前座標,相對於offset parent的座標。( offset parent指離該元素最近的並且被定位過的祖先元素 )
// jQuery $(el).position() // Native { left: el.offsetLeft, top: el.offsetTop }
將參數內容插入到每一個匹配元素的前面(元素內部)。
// jQuery $(el).prepend('<p></p>') // Native (HTML string) el.insertAdjacentHTML('afterbegin', '<p></p>') // Native (Element) el.insertBefore(newEl, el.firstChild)
與prepend相反
取得一個包含匹配的元素集合中每個元素緊鄰的前一個同輩元素的元素集合。選擇性篩選的選擇器。
與next相似
得到集合中每一個匹配元素的全部前面的兄弟元素,選擇性篩選的選擇器。
與nextAll相似
獲取每一個元素但不包括選擇器,DOM節點,或者jQuery對象匹配的元素的全部前面的兄弟元素。
與nextUntil相似
將匹配元素集合從DOM中刪除。(注:同時移除元素上的事件及 jQuery 數據。)
// jQuery $(el).remove() // Native el.parentNode.removeChild(el) // Native el.outerHTML = ''
爲匹配的元素集合中的每一個元素中移除一個屬性(attribute)。
// jQuery $(el).removeAttr(attr) // Native el.removeAttribute(attr)
移除集合中每一個匹配元素上一個,多個或所有樣式。
// jQuery $(el).removeClass(className) // Native (IE 10+ support) el.classList.remove(className)
與replaceWith相反
用提供的內容替換集合中全部匹配的元素而且返回被刪除元素的集合。
// jQuery $(el).replaceWith('<p></p>') // Native (HTML string) el.outerHTML = '<p></p>' // Native (Element) el.parentNode.replaceChild(newEl, el)
與scrollTop同樣
獲取匹配的元素集合中第一個元素的當前垂直滾動條的位置或設置每一個匹配元素的垂直滾動條位置。設置每一個匹配元素的垂直滾動條位置
// jQuery $(el).scrollTop() // Native (el is window) Math.max(document.documentElement.scrollTop, document.body.scrollTop) or window.pageYOffset // Native (el is not window) el.scrollTop // jQuery $(el).scrollTop(10) // Native (el is window) document.documentElement.scrollTop = 10 document.body.scrollTop = 10 // Native (el is not window) el.scrollTop = 10
得到匹配元素集合中每一個元素的兄弟元素,能夠提供一個可選的選擇器。。
// jQuery $(el).siblings() // Native
根據指定的下標範圍,過濾匹配的元素集合,並生成一個新的 jQuery 對象。
// jQuery $(selector).slice(1, 6) // Native $$(selector).slice(1, 6)
獲得匹配元素集合中每一個元素的合併文本,包括他們的後代設置匹配元素集合中每一個元素的文本內容爲指定的文本內容。
// jQuery $(el).text() // Native el.textContent // jQuery $(el).text(string) // Native el.textContent = string
在匹配的元素集合中的每一個元素上添加或刪除一個或多個樣式類,取決於這個樣式類是否存在或值切換屬性。即:若是存在(不存在)就刪除(添加)一個類。
// jQuery $(el).toggleClass(className) // Native el.classList.toggle(className)
將匹配元素集合的父級元素刪除,保留自身(和兄弟元素,若是存在)在原來的位置。
// jQuery $(el).unwrap() // Native const parent = el.parentNode parent.outerHTML = parent.innerHTML
獲取匹配的元素集合中第一個元素的當前值。設置匹配的元素集合中每一個元素的值。
// jQuery $(el).val() // Native el.value // jQuery $(el).val(value) // Native el.value = value
與height相似
在每一個匹配的元素外層包上一個html元素。
// jQuery $(el).wrap('<div class="wrapper"></div>') // Native const wrapper = document.createElement('div') wrapper.className = 'wrapper' el.parentNode.insertBefore(wrapper, el) el.parentNode.removeChild(el) wrapper.appendChild(el) // Native // 這種性能比較差 https://jsperf.com/outerhtml-appendchild el.outerHTML = `<div class="wrapper">${el.outerHTML}</div>`
經常使用的 class、id、屬性 選擇器均可以使用 document.querySelector
或 document.querySelectorAll
替代。區別是
document.querySelector
返回第一個匹配的 Element
document.querySelectorAll
返回全部匹配的 Element 組成的 NodeList。它能夠經過 [].slice.call()
把它轉成 Array
若是匹配不到任何 Element,jQuery 返回空數組 []
,但 document.querySelector
返回 null
,注意空指針異常。
注意:
document.querySelector
和document.querySelectorAll
性能很差。若是想提升性能,儘可能使用document.getElementById
、document.getElementsByClassName
或document.getElementsByTagName
。
如下只實現和jquery有所區別的api
選擇全部包含指定文本的元素。
// jQuery $('selector:contains("metchString")') // Native $$('selector').filter(el => el.textContent.indexOf('metchString') !== -1)
選擇全部沒有子元素的元素(包括文本節點)。
// jQuery $('selector:empty') // Native $$('selector').filter(el => el.innerHTML === '')
選擇索引值爲偶數的元素,從 0 開始計數。
// jQuery $('selector:even') // Native $$('selector').filter((el, index) => (index & 1) === 0)
選擇當前獲取焦點的元素。
// jQuery $(':focus') // Native document.activeElement
選擇匹配集合中全部大於給定index(索引值)的元素。
// jQuery $('selector:gt(2)') // Native $$('selector').filter((el, index) => index > 2)
與has相似
選擇全部標題元素,像h1, h2, h3 等.
// jQuery $('selector:header') // Native $$('selector').filter(el => /^h\d$/i.test(el.nodeName))
選擇匹配集合中全部索引值小於給定index參數的元素。
// jQuery $('selector:lt(2)') // Native $$('selector').filter((el, index) => index < 2)
與not相似
選擇索引值爲奇數元素,從 0 開始計數。
// jQuery $('selector:odd') // Native $$('selector').filter((el, index) => (index & 1) === 1)
若是某個元素是其父元素的惟一子元素,那麼它就會被選中。
// jQuery $('selector:only-child') // Native $$('selector').filter(el => el.previousElementSibling === null && el.nextElementSibling === null) // Native $$('selector').filter(el => el.parentNode.children.length === 1)
選擇器匹配屬於其父元素的特定類型的惟一子元素的每一個元素。
// jQuery $('selector:only-of-type') // Native $$('selector').filter(el => { for(let child of el.parentNode.children) { if (child !== el && child.nodeName === el.nodeName) { return true } } return false })
選擇全部含有子元素或者文本的父級元素。
// jQuery $('selector:parent') // Native $$('selector').filter(el => el.innerHTML !== '')
獲取 select 元素中全部被選中的元素。
// jQuery $('select option:selected') // Native (single) $('select option')[$('select').selectedIndex] // Native (multiple) $$('select option').filter(el => el.selected)
檢查一個DOM元素是另外一個DOM元素的後代。
// jQuery $.contains(el, child) // Native el !== child && el.contains(child)
一個通用的迭代函數,它能夠用來無縫迭代對象和數組。數組和相似數組的對象經過一個長度屬性(如一個函數的參數對象)來迭代數字索引,從0到length - 1。其餘對象經過其屬性名進行迭代。
// jQuery $.each(array, (index, value) => {}) // Native array.forEach((value, index) => {})
將兩個或更多對象的內容合併到第一個對象。
// jQuery $.extend({}, {a: 1}, {b: 2}) // {a: 1, b: 2} // ES6-way Object.assign({}, {a: 1}, {b: 2}) // {a: 1, b: 2}
在全局上下文下執行一些JavaScript代碼。
// jQuery $.globaleval(code) // Native function Globaleval(code) { const script = 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)
查找知足過濾函數的數組元素。原始數組不受影響。
// jQuery $.grep([10,11,3,4], n => n > 9) // Native [10,11,3,4].filter(n => n > 9)
在數組中查找指定值並返回它的索引(若是沒有找到,則返回-1)。
// jQuery $.inArray(item, array) // Native array.indexOf(item) > -1 // ES6-way array.includes(item)
肯定的參數是一個數組。
// jQuery $.isArray(array) // Native Array.isArray(array)
檢查對象是否爲空(不包含任何屬性)。
// jQuery $.isEmptyObject(obj) // Native function isEmptyObject(obj) { return Object.keys(obj).length === 0 }
肯定參數是否爲一個Javascript 函數。
// jQuery $.isFunction(item) // Native function isFunction(item) { if (typeof item === 'function') { return true } var type = Object.prototype.toString(item) return type === '[object Function]' || type === '[object GeneratorFunction]' }
肯定它的參數是不是一個數字。
// jQuery $.isNumeric(item) // Native function isNumeric(value) { var type = typeof value return (type === 'number' || type === 'string') && !isNaN(value - parseFloat(value)) }
測試對象是不是純粹的對象(經過 "{}" 或者 "new Object" 建立的)
// jQuery $.isPlainObject(obj) // Native function isPlainObject(obj) { if (typeof (obj) !== 'object' || obj.nodeType || obj !== null && obj !== undefined && obj === obj.window) { return false } if (obj.constructor && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, 'isPrototypeOf')) { return false } return true }
肯定參數是否爲一個window對象。
// jQuery $.isWindow(obj) // Native function isWindow(obj) { return obj !== null && obj !== undefined && obj === obj.window } // jquery源碼中是這麼判斷對象是否爲window的,個人理解是代碼可能會跑到服務器上,由於服務器上是沒有window對象的。因此這麼判斷
轉換一個相似數組的對象成爲真正的JavaScript數組。
// jQuery $.makeArray(arrayLike) // Native Array.prototype.slice.call(arrayLike) // ES6-way Array.from(arrayLike)
將一個數組中的全部元素轉換到另外一個數組中。
// jQuery $.map(array, (value, index) => { }) // Native array.map((value, index) => { })
合併兩個數組內容到第一個數組。
// jQuery $.merge(array1, array2) // Native // But concat function doesn't remove duplicate items. function merge(...args) { return [].concat(...args) }
返回一個數字,表示當前時間。
// jQuery $.now() // Native Date.now() // Native +new Date() // Native new Date().getTime()
將字符串解析到一個DOM節點的數組中。
// jQuery $.parseHTML(string) // Native function parseHTML(string) { const context = document.implementation.createHTMLDocument() // Set the base href for the created document so any parsed elements with URLs // are based on the document's URL const base = context.createElement('base') base.href = document.location.href context.head.appendChild(base) context.body.innerHTML = string return context.body.childNodes } // Native (IE 10+ support) // 二者性能差很少 https://jsperf.com/parsehtml2 function parseHTML(string) { const context = new DOMParser().parseFromString(string, "text/html") return context.body.childNodes }
接受一個標準格式的 JSON 字符串,並返回解析後的 JavaScript 對象。
// jQuery $.parseJSON(str) // Native JSON.parse(str)
解析一個字符串到一個XML文檔。
// jQuery jQuery.parseXML(xmlString) // Native new DOMParser().parseFromString(xmlString, 'application/xml')
接受一個函數,而後返回一個新函數,而且這個新函數始終保持了特定的上下文語境。
// jQuery $.proxy(fn, context) // Native fn.bind(context)
去掉字符串起始和結尾的空格。
// jQuery $.trim(string) // Native string.trim()
肯定JavaScript 對象的類型[[Class]] 。
// jQuery $.type(obj) // Native function type(item) { const reTypeOf = /(?:^\[object\s(.*?)\]$)/ return Object.prototype.toString.call(item) .replace(reTypeOf, '$1') .toLowerCase() }
有哪塊錯誤的或者不懂得能夠在github上提個issue。若是哪塊有更好的解法能夠pr。