SoxSaber / 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

前端发展很快,现代浏览器原生 API 已经足够好用。我们并不需要为了操作 DOM、Event 等再学习一下 jQuery 的 API。同时由于 React、Angular、Vue 等框架的流行,直接操作 DOM 不再是好的模式,jQuery 使用场景大大减少。本项目总结了大部分 jQuery API 替代的方法,暂时只支持 IE10+ 以上浏览器。

目录

Query Selector

常用的 class、id、属性 选择器都可以使用 document.querySelectordocument.querySelectorAll 替代。区别是

  • document.querySelector 返回第一个匹配的 Element
  • document.querySelectorAll 返回所有匹配的 Element 组成的 NodeList。它可以通过 [].slice.call() 把它转成 Array
  • 如果匹配不到任何元素,jQuery 返回空数组 [],但 document.querySelector返回返回null`,注意空指针异常
// 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');
// IE 11+ 开始支持 `dataset`
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

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

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

jQuery 对象的 iframe contents() 返回的是 iframe 内的 document

// 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");
// 注意:此处为了解决当 style 值为 auto 时,返回 auto 的问题
const win = el.ownerDocument.defaultView;
// null 的意思是不返回伪类元素
win.getComputedStyle(el, null).color;

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

注意,如果想一次设置多个 style,可以参考 oui-dom-utils 中 setStyles 方法

width, height

Width 与 Height 获取方法相同,下面以 Height 为例:

// window height
$(window).height();
// 不含 scrollbar,与 jQuery 行为一致
window.document.documentElement.clientHeight
// 含 scrollbar
window.innerHeight

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

// el height
$el.height();
// 与 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 .contents() 方法返回 iframe 的 contentDocument
$('iframe').contents().height()
iframe.contentDocument.documentElement.scrollHeight

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 插入到子节点的末尾

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


// 获取 e.currentTarget 相对于 .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