抛弃jQuery,拥抱原生JavaScript


前端发展很快,现代浏览器原生 API 已经足够好用。
我们并不需要为了操作 DOM、Event 等再学习一下 jQuery 的 API。
同时由于 React、Angular、Vue 等框架的流行,直接操作 DOM 不再是好的模式,jQuery 使用场景大大减少

YOU MIGHT NOT NEED JQUERY

jQuery and its cousins are great, and by all means use them if it makes it easier to develop your application.

If you're developing a library on the other hand, please take a moment to consider if you actually need jQuery as a dependency. Maybe you can include a few lines of utility code, and forgo the requirement. If you're only targeting more modern browsers, you might not need anything more than what the browser ships with.

At the very least, make sure you know what jQuery is doing for you, and what it's not. Some developers believe that jQuery is protecting us from a great demon of browser incompatibility when, in truth, post-IE8, browsers are pretty easy to deal with on their own.

Your search didn't match any comparisons.

AJAX

Alternatives: reqwest, then-request, superagent

jQuery

$.getJSON('/my/url', function(data) {
});
            

IE8+

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);

request.onreadystatechange = function() {
  if (this.readyState === 4) {
    if (this.status >= 200 && this.status < 400) {
      // Success!
      var data = JSON.parse(this.responseText);
    } else {
      // Error :(
    }
  }
};

request.send();
request = null;
      

IE9+

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);

request.onload = function() {
if (request.status >= 200 && request.status < 400) {
  // Success!
  var data = JSON.parse(request.responseText);
} else {
  // We reached our target server, but it returned an error

}
};

request.onerror = function() {
// There was a connection error of some sort
};

request.send();

IE10+

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);

request.onload = function() {
if (this.status >= 200 && this.status < 400) {
  // Success!
  var data = JSON.parse(this.response);
} else {
  // We reached our target server, but it returned an error

}
};

request.onerror = function() {
// There was a connection error of some sort
};

request.send();

jQuery

$.ajax({
type: 'POST',
url: '/my/url',
data: data
});

IE8+

var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send(data);

jQuery

$.ajax({
type: 'GET',
url: '/my/url',
success: function(resp) {

},
error: function() {

}
});

IE8+

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);

request.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status >= 200 && this.status < 400) {
// Success!
var resp = this.responseText;
} else {
// Error :(
}
}
};

request.send();
request = null;

IE9+

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);

request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = request.responseText;
} else {
// We reached our target server, but it returned an error

}
};

request.onerror = function() {
// There was a connection error of some sort
};

request.send();

IE10+

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);

request.onload = function() {
if (this.status >= 200 && this.status < 400) {
// Success!
var resp = this.response;
} else {
// We reached our target server, but it returned an error

}
};

request.onerror = function() {
// There was a connection error of some sort
};

request.send();

Effects

Alternatives: animate.css, move.js

jQuery

$(el).fadeIn();
  

IE8+

function fadeIn(el) {
  var opacity = 0;

  el.style.opacity = 0;
  el.style.filter = '';

  var last = +new Date();
  var tick = function() {
  opacity += (new Date() - last) / 400;
  el.style.opacity = opacity;
  el.style.filter = 'alpha(opacity=' + (100 * opacity)|0 + ')';

  last = +new Date();

  if (opacity < 1) {
  (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
  }
  };

  tick();
  }

  fadeIn(el);
  

IE9+

function fadeIn(el) {
  el.style.opacity = 0;

  var last = +new Date();
  var tick = function() {
  el.style.opacity = +el.style.opacity + (new Date() - last) / 400;
  last = +new Date();

  if (+el.style.opacity < 1) {
  (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
  }
  };

  tick();
  }

  fadeIn(el);
  

IE10+

el.classList.add('show');
  el.classList.remove('hide');
  
.show {
  transition: opacity 400ms;
  }
  .hide {
  opacity: 0;
  }
  

jQuery

$(el).hide();
  

IE8+

el.style.display = 'none';
  

jQuery

$(el).show();
  

IE8+

el.style.display = '';
  

Elements

Alternatives: bonzo, $dom

jQuery

$(el).addClass(className);
  

IE8+

if (el.classList)
  el.classList.add(className);
  else
  el.className += ' ' + className;
  

IE10+

el.classList.add(className);
  

jQuery

$(el).after(htmlString);
  

IE8+

el.insertAdjacentHTML('afterend', htmlString);
  

jQuery

$(parent).append(el);
  

IE8+

parent.appendChild(el);
  

jQuery

$(el).before(htmlString);
  

IE8+

el.insertAdjacentHTML('beforebegin', htmlString);
  

jQuery

$(el).children();
  

IE8+

var children = [];
  for (var i = el.children.length; i--;) {
  // Skip comment nodes on IE8
  if (el.children[i].nodeType != 8)
  children.unshift(el.children[i]);
  }
  

IE9+

el.children
  

jQuery

$(el).clone();
  

IE8+

el.cloneNode(true);
  

jQuery

$.contains(el, child);
  

IE8+

el !== child && el.contains(child);
  

jQuery

$(el).find(selector).length;
  

IE8+

el.querySelector(selector) !== null
  

jQuery

$(selector).each(function(i, el){

  });
  

IE8+

function forEachElement(selector, fn) {
  var elements = document.querySelectorAll(selector);
  for (var i = 0; i < elements.length; i++)
  fn(elements[i], i);
  }

  forEachElement(selector, function(el, i){

  });
  

IE9+

var elements = document.querySelectorAll(selector);
  Array.prototype.forEach.call(elements, function(el, i){

  });
  

jQuery

$(el).empty();

IE8+

while(el.firstChild)
el.removeChild(el.firstChild);

IE9+

el.innerHTML = '';

jQuery

$(selector).filter(filterFn);

IE8+

function filter(selector, filterFn) {
var elements = document.querySelectorAll(selector);
var out = [];
for (var i = elements.length; i--;) {
if (filterFn(elements[i]))
out.unshift(elements[i]);
}
return out;
}

filter(selector, filterFn);

IE9+

Array.prototype.filter.call(document.querySelectorAll(selector), filterFn);

jQuery

$(el).find(selector);

IE8+

el.querySelectorAll(selector);

Find Elements

Alternatives: qwery, sizzle

jQuery

$('.my #awesome selector');

IE8+

document.querySelectorAll('.my #awesome selector');

jQuery

$(el).attr('tabindex');

IE8+

el.getAttribute('tabindex');

jQuery

$(el).html();

IE8+

el.innerHTML

jQuery

$('<div>').append($(el).clone()).html();

IE8+

el.outerHTML

jQuery

$(el).css(ruleName);

IE8+

// Varies based on the properties being retrieved, some can be retrieved from el.currentStyle
// https://github.com/jonathantneal/Polyfills-for-IE8/blob/master/getComputedStyle.js

IE9+

getComputedStyle(el)[ruleName];

jQuery

$(el).text();

IE8+

el.textContent || el.innerText

IE9+

el.textContent

jQuery

$(el).hasClass(className);

IE8+

if (el.classList)
el.classList.contains(className);
else
new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);

IE10+

el.classList.contains(className);

jQuery

$(el).is($(otherEl));

IE8+

el === otherEl

jQuery

$(el).is('.my-class');

IE8+

var matches = function(el, selector) {
var _matches = (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector);

if (_matches) {
return _matches.call(el, selector);
} else {
var nodes = el.parentNode.querySelectorAll(selector);
for (var i = nodes.length; i--;) {
if (nodes[i] === el)
return true;
}
return false;
}
};

matches(el, '.my-class');

IE9+

var matches = function(el, selector) {
return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector);
};

matches(el, '.my-class');

jQuery

$(el).offset();

IE8+

var rect = el.getBoundingClientRect();

{
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
}

jQuery

$(el).offsetParent();

IE8+

el.offsetParent || el

jQuery

$(el).outerHeight();

IE8+

el.offsetHeight

jQuery

$(el).outerHeight(true);

IE8+

function outerHeight(el) {
var height = el.offsetHeight;
var style = el.currentStyle || getComputedStyle(el);

height += parseInt(style.marginTop) + parseInt(style.marginBottom);
return height;
}

outerHeight(el);

IE9+

function outerHeight(el) {
var height = el.offsetHeight;
var style = getComputedStyle(el);

height += parseInt(style.marginTop) + parseInt(style.marginBottom);
return height;
}

outerHeight(el);

jQuery

$(el).outerWidth();

IE8+

el.offsetWidth

jQuery

$(el).outerWidth(true);

IE8+

function outerWidth(el) {
var width = el.offsetWidth;
var style = el.currentStyle || getComputedStyle(el);

width += parseInt(style.marginLeft) + parseInt(style.marginRight);
return width;
}

outerWidth(el);

IE9+

function outerWidth(el) {
var width = el.offsetWidth;
var style = getComputedStyle(el);

width += parseInt(style.marginLeft) + parseInt(style.marginRight);
return width;
}

outerWidth(el);

jQuery

$(el).parent();

IE8+

el.parentNode

jQuery

$(el).position();

IE8+

{left: el.offsetLeft, top: el.offsetTop}

jQuery

var offset = el.offset();

{
top: offset.top - document.body.scrollTop,
left: offset.left - document.body.scrollLeft
}

IE8+

el.getBoundingClientRect()

jQuery

$(parent).prepend(el);

IE8+

parent.insertBefore(el, parent.firstChild);

jQuery

$(el).remove();

IE8+

el.parentNode.removeChild(el);

jQuery

$(el).removeClass(className);

IE8+

if (el.classList)
el.classList.remove(className);
else
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');

IE10+

el.classList.remove(className);

jQuery

$(el).replaceWith(string);

IE8+

el.outerHTML = string;

jQuery

$(el).attr('tabindex', 3);

IE8+

el.setAttribute('tabindex', 3);

jQuery

$(el).html(string);

IE8+

el.innerHTML = string;

jQuery

$(el).css('border-width', '20px');

IE8+

// Use a class if possible
el.style.borderWidth = '20px';

jQuery

$(el).text(string);

IE8+

if (el.textContent !== undefined)
el.textContent = string;
else
el.innerText = string;

IE9+

el.textContent = string;

jQuery

$(el).siblings();

IE8+

var siblings = Array.prototype.slice.call(el.parentNode.children);

for (var i = siblings.length; i--;) {
if (siblings[i] === el) {
siblings.splice(i, 1);
break;
}
}

IE9+

Array.prototype.filter.call(el.parentNode.children, function(child){
return child !== el;
});

jQuery

$(el).toggleClass(className);
  

IE8+

if (el.classList) {
  el.classList.toggle(className);
  } else {
  var classes = el.className.split(' ');
  var existingIndex = -1;
  for (var i = classes.length; i--;) {
  if (classes[i] === className)
  existingIndex = i;
  }

  if (existingIndex >= 0)
  classes.splice(existingIndex, 1);
  else
  classes.push(className);

  el.className = classes.join(' ');
  }
  

IE9+

if (el.classList) {
  el.classList.toggle(className);
  } else {
  var classes = el.className.split(' ');
  var existingIndex = classes.indexOf(className);

  if (existingIndex >= 0)
  classes.splice(existingIndex, 1);
  else
  classes.push(className);

  el.className = classes.join(' ');
  }
  

IE10+

el.classList.toggle(className);
  

Events

Off

jQuery

$(el).off(eventName, eventHandler);

IE8+

function removeEventListener(el, eventName, handler) {
if (el.removeEventListener)
el.removeEventListener(eventName, handler);
else
el.detachEvent('on' + eventName, handler);
}

removeEventListener(el, eventName, handler);

IE9+

el.removeEventListener(eventName, eventHandler);

On

jQuery

$(el).on(eventName, eventHandler);

IE8+

function addEventListener(el, eventName, handler) {
if (el.addEventListener) {
el.addEventListener(eventName, handler);
} else {
el.attachEvent('on' + eventName, function(){
handler.call(el);
});
}
}

addEventListener(el, eventName, handler);

IE9+

el.addEventListener(eventName, eventHandler);

jQuery

$(document).ready(function(){

});

IE8+

function ready(fn) {
if (document.readyState != 'loading'){
fn();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', fn);
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState != 'loading')
fn();
});
}
}

IE9+

function ready(fn) {
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading"){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}

jQuery

$(el).trigger('my-event', {some: 'data'});

IE8+

// Custom events are not natively supported, so you have to hijack a random
// event.
//
// Just use jQuery.

IE9+

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

el.dispatchEvent(event);

jQuery

$(el).trigger('change');

IE8+

if (document.createEvent) {
var event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
el.dispatchEvent(event);
} else {
el.fireEvent('onchange');
}

IE9+

// For a full list of event types: https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent
var event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
el.dispatchEvent(event);

Utils

jQuery

$.proxy(fn, context);

IE8+

fn.apply(context, arguments);

IE9+

fn.bind(context);

jQuery

$.each(array, function(i, item){

});

IE8+

function forEach(array, fn) {
for (var i = 0; i < array.length; i++)
fn(array[i], i);
}

forEach(array, function(item, i){

});

IE9+

array.forEach(function(item, i){

});

jQuery

$.extend(true, {}, objA, objB);

IE8+

var deepExtend = function(out) {
out = out || {};

for (var i = 1; i < arguments.length; i++) {
var obj = arguments[i];

if (!obj)
continue;

for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object')
  out[key] = deepExtend(out[key], obj[key]);
else
  out[key] = obj[key];
}
}
}

return out;
};

deepExtend({}, objA, objB);

Extend

Alternatives: lo-dash, underscore, ECMA6

jQuery

$.extend({}, objA, objB);

IE8+

var extend = function(out) {
out = out || {};

for (var i = 1; i < arguments.length; i++) {
if (!arguments[i])
continue;

for (var key in arguments[i]) {
if (arguments[i].hasOwnProperty(key))
out[key] = arguments[i][key];
}
}

return out;
};

extend({}, objA, objB);

jQuery

$.inArray(item, array);

IE8+

function indexOf(array, item) {
for (var i = 0; i < array.length; i++) {
if (array[i] === item)
return i;
}
return -1;
}

indexOf(array, item);

IE9+

array.indexOf(item);

jQuery

$.isArray(arr);

IE8+

isArray = Array.isArray || function(arr) {
return Object.prototype.toString.call(arr) == '[object Array]';
};

isArray(arr);

IE9+

Array.isArray(arr);

Map

jQuery

$.map(array, function(value, index){

});

IE8+

function map(arr, fn) {
var results = [];
for (var i = 0; i < arr.length; i++)
results.push(fn(arr[i], i));
return results;
}

map(array, function(value, index){

});

IE9+

array.map(function(value, index){

});

Now

jQuery

$.now();

IE8+

new Date().getTime();

IE9+

Date.now();

jQuery

$.parseHTML(htmlString);

IE8+

var parseHTML = function(str) {
var el = document.createElement('div');
el.innerHTML = str;
return el.children;
};

parseHTML(htmlString);

IE9+

var parseHTML = function(str) {
var tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = str;
return tmp.body.children;
};

parseHTML(htmlString);

jQuery

$.parseJSON(string);

IE8+

JSON.parse(string);

jQuery

$.trim(string);

IE8+

string.replace(/^\s+|\s+$/g, '');

IE9+

string.trim();

jQuery

$.type(obj);

IE8+

Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();