mindaugasva / You-Dont-Need-jQuery

You don't need jQuery any more, here is how you can get ride of it.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

You Don't Need jQuery

Frontend environment evolves repaidly nowadays, modern browsers have already implemented a great deal of DOM/BOM APIs which are good enough. We don't have to learn jQuery from scratch for DOM manipulation or events. In the meantime, thanks to the prevail of frontend libraries like React, Angular and Vue, manipulating DOM directly becomes anti-pattern, jQuery has never been less important. This project summarized most of the jQuery method alternatives in native implementation, with IE 10+ support.

Translation

Catalog

Query Selector

Common selectors like class, id or attribute we can use document.querySelector or document.querySelectorAll for substitution. The differences lie in:

  • document.querySelector returns the first matched Element
  • document.querySelectorAll returns all matched Elements as NodeList. It can be converted to Array using [].slice.call
  • If no element matched, jQuery would return [] whereas these DOM API will return null. Pay attention to Null Pointer Exception.
// query by class
$('.css')
document.querySelectorAll('.css')

// query by id
$('#id')
el.querySelectorAll('#id')

// query by attribute
$('a[target=_blank]')
document.querySelectorAll('a[target=_blank]')
 
// find
$el.find('li')
el.querySelectorAll('li')

// body
$('body')
document.body

// attr
$el.attr('foo')
e.getAttribute('foo')

// data attribute
$el.data('foo')
// using getAttribute
el.getAttribute('data-foo');
// you can also use `dataset` if only need to support IE 11+
el.dataset['foo']

// siblings
$el.siblings();
[].filter.call(el.parentNode.children, function(child) {
	return child !== el;
})

// prev
$el.prev();
el.previousElementSibling

// next
$el.next();
el.nextElementSibling

closest

return the first matched element by provided selector, traversing from current element to document.

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;
 }

parentsUntil

Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object.

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;
}

iframe contents

$('iframe').contents() returns contentDocument for this specific iframe

// contents
$iframe.contents()
iframe.contentDocument

// query
$iframe.contents().find('.css')
iframe.contentDocument.querySelectorAll('.css')

css style

// set css
$el.css('border-width', 20)
el.style.borderWidth = '20px'

// addClass
$el.addClass(className)
el.classList.add(className);

// removeClass
$el.removeClass(className)
el.classList.remove(className);

// hasClass
$el.hasClass(className)
el.classList.contains(className);

// toggleClass
$el.toggleClass(className)
el.classList.toggle(className);

// get style
$el.css("color");
// NOTE: Known bug, will return 'auto' if style value is 'auto'
const win = el.ownerDocument.defaultView;
// null means not return presudo styles
win.getComputedStyle(el, null).color;

// set style
$el.css({ color: "#ff0011" });
el.style.color = '#ff0011'; 

Note that if you want to set multiple styles once, you could refer to setStyles method in oui-dom-utils package.

width, height

Width and Height are theoretically identical, take Height as example:

// window height
$(window).height();
// without scrollbar, behaves like jQuery
window.document.documentElement.clientHeight
// with scrollbar
window.innerHeight

// document height
$(document).height();
document.documentElement.scrollHeight

// el height
$el.height();
// behaves like jQuery
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;
}
// accurate to integer(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`)
el.clientHeight
// accurate to decimal(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`)
el.getBoundingClientRect().height

position, offset

// position
$el.position();
{ left: el.offsetLeft, top: el.offsetTop }

// offset
$el.offset();
function getOffset (el) {
  let box = el.getBoundingClientRect();
  return {
	  top: box.top + window.pageYOffset - document.documentElement.clientTop,
    left: box.left + window.pageXOffset - document.documentElement.clientLeft
  }
}

DOM Manipulation

// remove
$el.remove()
el.parentNode.removeChild(el);

// get text
$el.text()
el.textContent

// set text
$el.text(string)
el.textContent = string

// get html
$el.html()
el.innerHTML

// set html
$el.html(htmlString)
el.innerHTML = htmlString

append

append child element after the last child of parent element

jQuery

$el.append("<div id='container'>hello</div>")

Native

let newEl = document.createElement('div');
newEl.setAttribute('id', 'container');
newEl.innerHTML = 'hello';
el.appendChild(newEl)

prepend

jQuery

$el.prepend("<div id='container'>hello</div>")

Native

let newEl = document.createElement('div')
newEl.setAttribute('id', 'container')
newEl.innerHTML = 'hello'
el.insertBefore(newEl, el.firstChild)

insertBefore

Insert a new node before the selected elements

jQuery

$newEl.insertBefore(queryString);

Native

newEl.insertBefore(document.querySelector(queryString))

insertAfter

Insert a new node after the selected elements

jQuery

$newEl.insertAfter(queryString);

Native

function insertAfter(newEl, queryString) {
  var parent = document.querySelector(queryString).parentNode;

  if (parent.lastChild === newEl) {
    parent.appendChild(newEl);
  } else {
    parent.insertBefore(newEl, parent.nextSibling);
  }
},

scrollTop

// scrollTop
$(window).scrollTop()
(document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;

Ajax

Replace with fetch and fetch-jsonp

Events

For a complete replacement with namespace and delegation, refer to https://github.com/oneuijs/oui-dom-events

// bind an event with on
$el.on(eventName, eventHandler);
el.addEventListener(eventName, eventHandler);

// unbind an event with off
$el.off(eventName, eventHandler);
el.removeEventListener(eventName, eventHandler);

trigger

jQuery

$(el).trigger('custom-event', {key1: 'data'});

Native

if (window.CustomEvent) {
  var event = new CustomEvent('custom-event', {detail: {key1: 'data'}});
} else {
  var event = document.createEvent('CustomEvent');
  event.initCustomEvent('custom-event', true, true, {key1: 'data'});
}

el.dispatchEvent(event);

Form

$('#my-input').val()
document.querySelector('#my-input').value


// get index of e.currentTarget between `.radio` 
$(e.currentTarget).index('.radio')
[].indexOf.call(document.querySelectAll('.radio'), e.currentTarget)

Utilities

// isArray IE10+
$.isArray(range)
Array.isArray(range)

// trim
$.trim(string)
String.trim(string)

// extend, use object.assign polyfill https://github.com/ljharb/object.assign
$.extend({}, defaultOpts, opts)
Object.assign({}, defaultOpts, opts)

// contains
$.contains(el, child);
el !== child && el.contains(child);

Browser Support

Chrome Firefox IE Opera Safari
Latest ✔ Latest ✔ 10+ ✔ Latest ✔ 6.1+ ✔

License

MIT

About

You don't need jQuery any more, here is how you can get ride of it.

License:MIT License