(轉自公眾號:前端八點半,已授權)
前言
在MV*框架興起,前端告別刀耕火種進入工程化的今天,還沒來得及學習Angular,Facebook就帶著react框架降臨,不久vue.js又在這些框架打得火熱的時候脫穎而出,各種框架充斥著我們的視覺神經,好像操作DOM來寫前端的思想已經退出了歷史舞臺。而jQuery作為那個年代前端er主要的庫,對於DOM的增刪改查的便利讓我們對jQuery頂禮膜拜,jQuery為了簡化js而生,卻又因簡化js而死,jQuery釋出第一版距今已經11年之久,而後jQuery時代,我們需要怎麼做?
第一版jQuery誕生於2006年,當初jQuery的誕生有兩個目的,第一簡化DOM操作,第二減少開發過程中跨瀏覽器的問題。
他的創始人John Resig給這些程式碼新增了註釋,如下有第一版jQuery的地址,你可以第一版的原始碼。genius.it/johnresig.c…
jQuery是偉大的,但是在當下技術發展的今天,我們不需要再相容IE6和IE7的情況下,很多相容性問題瀏覽器已經自行解決了,所以說,將jQuery從你的網站中刪除是正確的做法。而且js現在已經更加簡潔,對於很多DOM操作,用原生js來寫也會非常簡潔。
jQuery速覽
1.文件載入後執行:
$(document).ready(function(){})
$(function(){})
複製程式碼
2.jQuery事件繫結on
、bind
、live
、delegate
3.jQuery增刪改查
增加:append()
- 在被選元素的結尾插入內容prepend()
- 在被選元素的開頭插入內容after()
- 在被選元素之後插入內容appendTo()
- 把所有匹配的元素追加到指定的元素元素集合中。
刪除:remove()
- 刪除被選元素(及其子元素)
$("p").remove(".italic");
複製程式碼
empty()
- 從被選元素中刪除子元素
$("#div1").empty();
複製程式碼
修改:
設定內容- text()
、html()
以及 val()
text()
- 設定或返回所選元素的文字內容
$("#test1").text("Hello world!");
複製程式碼
html()
- 設定或返回所選元素的內容(包括 HTML 標記)
$("#test2").html("Hello world!");
複製程式碼
val()
- 設定或返回表單欄位的值
$("#test3").val("Dolly Duck");
複製程式碼
設定屬性- attr()
jQuery attr()
方法也用於設定/改變屬性值。
attr設定多個值
$("#w3s").attr({
"href" : "http://www.w3school.com.cn/jquery",
"title" : "W3School jQuery Tutorial"
});
複製程式碼
獲取:
獲得內容- text()
、html()
以及 val()
粗體文字text()
- 設定或返回所選元素的文字內容html()
- 設定或返回所選元素的內容(包括 HTML 標記)val()
- 設定或返回表單欄位的值
獲取屬性- attr()
jQuery attr() 方法用於獲取屬性值
$("#w3s").attr("href")
複製程式碼
查詢:
1.基本過濾器:
a) :first
,選取第一個元素,別忘記它也是被放在一個集合裡哦!因為JQuery它是DOM物件的一個集合。如,“$(“tr:first”)”返回所有tr元素的第一個tr元素,它仍然被儲存在集合中。
b) :last
,選取最後一個元素。如:“$(“tr:last”)”返回所有tr元素的最後一個tr元素,它仍然被儲存在集合中。
c):even
、:odd
奇偶過濾器
d):not
選擇所有不符合的元素
e):eq
選擇索引匹配的元素
2.子元素過濾器:first-child
(:last-child
)選擇所有父級元素下的第一個(最後一個)子元素。:first-of-type
(:last-of-type
)選擇所有相同的元素名稱的第一個(最後一個)兄弟元素:nth-child(n)
選擇的他們所有父元素的第n個子元素。:nth-last-child(n)
選擇所有他們父元素的第n個子元素。計數從最後一個元素開始到第一個。:nth-of-type(n)
選擇同屬於一個父元素之下,並且標籤名相同的子元素中的第n個。find(selector)
查詢該節點所有的子孫節點children(selector)
查詢所有的子節點,不過該方法只會返回直接的子節點,不會返回所有的子孫節點
3.父元素過濾器parent(selector)
查詢父元素,可傳入selector進行過濾(下同)parents(selector)
查詢所有的祖先節點
4.兄弟元素過濾器siblings()
查詢該節點所有的兄弟節點,不分前後prev()
查詢該節點的上一個兄弟節點prevAll()
查詢該節點之前所有的節點next()
查詢該節點的下一個兄弟節點nextAll()
查詢該節點之後所有的節點
去除DOM依賴
如何在專案中去除jQuery依賴,以及如何使用原生js替代jQuery中方法?
1.查詢DOMgetElementById()
:通過id查詢元素,訪問DOM最快的方法,而且大部分瀏覽器都支援getElementsByClassName()
:通過class查詢元素
注:上面兩個方法很快,但由於僅通過類名選擇元素的限制,作用有限。
//polyfill,實現getElementsByClassName
function getElementsByClassName(className) {
var all = document.all ? document.all : document.getElementsByTagName('*');
var elements = new Array();
for (var e = 0; e < all.length; e++) {
if (all[e].className == className) {
elements[elements.length] = all[e];
break;
}
}
return elements;
}
複製程式碼
querySelector()
和querySelectorAll()
:匹配指定 CSS 選擇器元素的第一個子元素(全部元素)。
注:querySelectorAll
獲取到的是一個類陣列,可以通過Array.prototype.slice.call()
將類陣列轉為陣列。
// jquery選擇器部分實現,container引數可選,獲取全部符合的元素
function $(selector, container) {
return (container || document).querySelectorAll(selector);
}
// 獲取一個符合的元素
function $one(selector, container) {
return (container || document).querySelector(selector);
}
複製程式碼
getElementsByTagName
:通過標籤名查詢元素,跨瀏覽器安全快速的方法,獲取到一個類陣列。
2.查詢遍歷
獲取父類元素-parentNode
獲取子類元素-childNode
,firstChild
,lastChild
獲取同級元素-nextSibling
、previousSibling
,只獲取一個匹配的
//獲取全部的同級元素
function getSiblings(el, filter) {
var siblings = [];
el = el.parentNode.firstChild;
do { if (!filter || filter(el)) siblings.push(el); } while (el = el.nextSibling);
return siblings;
}
複製程式碼
匹配特定選擇器且離當前元素最近的祖先元素-closest()
[實驗中的功能,有的瀏覽器不相容]
// polyfill,不相容瀏覽器的實現方法
this.Element && function(ElementPrototype) {
ElementPrototype.closest = ElementPrototype.closest ||
function(selector) {
var el = this;
while (el.matches && !el.matches(selector)) el = el.parentNode;
return el.matches ? el : null;
}
}(Element.prototype);
複製程式碼
matches()
:如果元素將被指定的選擇器字串選擇,Element.matches()
方法返回true
; 否則返回false
。
//polyfill
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
複製程式碼
3.DOM操作
建立DOM-createElement
替換DOM-replaceChild
刪除DOM(從DOM中刪除元素的父元素,使元素的內容保持原樣)
/*
*刪除element,但是保留element裡面的子元素的做法
*/
var element = document.querySelector('.container');
// 獲取元素的父元素
var parent = element.parentNode;
// 遍歷將所有子元素從這個元素中移出去
while (element.firstChild) parent.insertBefore(element.firstChild, element);
// 刪除這個元素
parent.removeChild(element);
清空元素的內容-DOM中刪除元素的所有子節點。
var el = document.querySelector('div');
//通過設定innerHTML為空清空所有子節點
el.innerHTML = '';
刪除DOM-removeChild方法從DOM中刪除一個子節點。返回刪除的節點。
//從parent中刪除child,函式的返回值也是child的引用
parent.removeChild(child);
插入DOM-insertBefore、appendChild
//insertBefore,在parent節點中將child節點插入到node1之前
parent.insertBefore(child, node1);
//appendChild,將child節點插入到parent的最尾部
parent.appendChild(child)
複製程式碼
獲取元素的text內容-textContent
、innerText
(IE8)
let node = document.querySelector('container');
let text = node.textContent || node.innerText;
複製程式碼
獲取/設定元素的HTML內容-innerHTML
屬性
複製當前節點(或者複製當前節點以及它的所有子孫節點)-cloneNode()
4.屬性操作-用於獲取和設定元素的DOM屬性的功能
設定、獲取和刪除DOM元素屬性
原生JavaScript可一直接訪問元素的屬性,例如:href
、title
、alt
、value
,刪除這些屬性的可以使用delete
關鍵字
var node = document.querySelector('selector');
//設定屬性property
node.property = ''
//使用delete刪除property屬性
delete node.property;
新增,刪除和測試class
//判斷node是否有className
function hasClass(node, className) {
return node.classList ?
node.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(node.className);
}
//新增class
function addClass(node, className) {
if (node.classList) {
node.classList.add(className);
}
else if (!hasClass(node, className)) {
node.className += ' ' + className;
}
}
//移除class
function removeClass(node, className) {
if (node.classList) {
node.classList.remove(className);
}
else {
node.className = node.className.replace(new RegExp('\\b' + className + '\\b', 'g'), '');
}
}
複製程式碼
獲取,設定和刪除屬性-getAttribute
、setAttribute
、removeAttribute
let node = document.querySelector('selector');
//在node上設定myProp屬性值為mydata
node.setAttribute('myProp', 'mydata');
//獲取myProp屬性
console.log(node.getAttribute('myProp'));
//刪除myProp屬性
node.removeAttribute('myProp');
複製程式碼
5.獲取設定元素樣式
樣式獲取-getComputedStyle
(IE9以下:currentStyle
)
var node = document.querySelector('selector');
// IE上使用currentStyle
var style = window.getComputedStyle ? getComputedStyle(node, null) : node.currentStyle;
複製程式碼
樣式設定- style
、cssText
function setCss(node, styles) {
for (var property in styles){
node.style[property] = styles[property];
}
}
//使用cssText能夠同時設定多個樣式
node.style.cssText += 'color:red;'
複製程式碼
各種位置獲取如下:
獲取並設定元素的滾動位置-scrollTop
、scrollLeft
獲取元素相對於其父元素的偏移位置-offsetLeft
、offsetTop
獲取相對於文件的元素的位置-getBoundingClientRect
function offset(node) {
let rect = node.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return { top: rect.top + scrollTop, left: rect.left + scrollLeft }
}
複製程式碼
獲取元素的寬度和高度-根據盒模型,元素包含margin
、border
、padding
、content
(width
+height
)
獲取content
+padding
+border
:offsetWidth
/offsetHeight
獲取content
+padding
:clientWidth
/clientHeight
獲取margin
、border
、padding
的值可以通過getComputedStyle
獲取視窗的寬高:window.innerWidth
、window.innerHeight
獲取文件的寬高:document.documentElement.clientWidth/Height
、
6.原生ajaxget
請求和post
請求
function getRequest(url, success) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('GET', url);
xhr.onreadystatechange = function () {
if (xhr.readyState > 3 && xhr.status == 200) success(xhr.responseText);
};
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send();
return xhr;
}
function postRequest(url, data, success) {
var params = typeof data == 'string' ? data : Object.keys(data).map(
function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }
).join('&');
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xhr.open('POST', url);
xhr.onreadystatechange = function() {
if (xhr.readyState>3 && xhr.status==200) { success(xhr.responseText); }
};
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(params);
return xhr;
}
複製程式碼
非同步載入js,async
或者defer
關鍵字也可以非同步
//1.通過動態插入script標籤非同步載入
let scriptNode = document.createElement('script'),
htmlNode = document.getElementsByTagName('script')[0];
scriptNode.src = url;
scriptNode.parentNode.insertBefore(scriptNode, htmlNode);
//2.通過async和defer屬性來非同步載入
<script src="" async defer></script>
複製程式碼
7.原生事件
阻止冒泡:
window.event? window.event.cancelBubble = true : e.stopPropagation();
複製程式碼
阻止預設事件:
window.event? window.event.returnValue = false : e.preventDefault();
複製程式碼
獲取鍵盤點選:
var key = window.event ? event.keyCode : event.which;
console.log(key);
複製程式碼
獲取滑鼠點選位置:
function handler(event) {
event = event || window.event;
let pageX = event.pageX;
let pageY = event.pageY;
// IE 8
if (pageX === undefined) {
pageX = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
pageY = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return {
pageX:pageX,
pageY:pageY
}
}
複製程式碼
事件繫結和解綁:
//新增事件
function addEvent(node, type, handler) {
if (node.attachEvent) {
node.attachEvent('on'+type, handler);
} else {
node.addEventListener(type, handler);
}
}
//解除繫結
function removeEvent(node, type, handler) {
if (node.detachEvent) {
node.detachEvent('on'+type, handler);
} else {
node.removeEventListener(type, handler);
}
}
複製程式碼
文件載入事件:
//對應於$(document).ready()的原生實現
document.addEventListener('DOMContentLoaded', function(){});
複製程式碼
(end)