原文鏈接:http://blog.garstasio.com/you-dont-need-jquery/dom-manipulation/
我的Blog:http://cabbit.me/you-dont-need-jquery/manipulation/
在上一篇文章里我們討論了如何在沒有jQuery的支持下選擇元素,這次我們來聊一聊如何使用DOM API創建新元素、修改已有元素的屬性或者移動元素的位置。原生的瀏覽器API已經給我們提供了DOM操作的所有功能,我們能夠不借助jQuery或者其他函數庫的幫助就完成這些。
當然有些操作會顯得比較冗長,所以我必須再強調一遍,這系列文章的用意不是讓開發人員不分情況的徹底丟棄jQuery,而是希望我們能夠在沒有jQuery的幫助時也能完成這些任務。在實際生產中我們依然會使用各種函數庫,但是我們可以仔細選擇,使用更加適合我們需要的庫,而不是部分情況的把整個jQuery都加載到頁面里。
創建元素
jQuery
如果我們要創建一個 div 元素:
$('<div></div>');
DOM API,createElement這個很常見了:
// IE 5.5+
document.createElement('div');
或許有人會說,jQuery省去了好些字符。這沒錯,但確實要依照工程實際而定,如果我們只是用到jQuery的小部分功能,那省去的字數可能還沒有jQuery自身的文件大。
在元素前/后插入元素
假設我們已經有了如下HTML結構:
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
現在我們要在 id=1 的 div 后面插入一個 id=1.1 的新 div 元素,期望的結果是這樣的:
<div id="1"></div>
<div id="1.1"></div>
<div id="2"></div>
<div id="3"></div>
jQuery
$('#1').after('<div id="1.1"></div>');
DOM API,有Web開發新人會認為鏈式調用是jQuery的專利,事實上沒有jQuery我們也可以使用鏈式調用:
// IE 4+
document.getElementById('1')
.insertAdjacentHTML('afterend', '<div id="1.1"></div>');
哈哈,這可能是DOM API里不多的從IE 4開始就沒怎么變化過的函數了~
假設我們希望在 id=1 的 div 前面插入一個 id=0.9 的新 div 元素,期望的結果是這樣:
<div id="0.9"></div>
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
jQuery
$('#1').before('<div id="0.9"></div>');
DOM API
// IE 4+
document.getElementById('1')
.insertAdjacentHTML('beforebegin', '<div id="0.9"></div>');
同在后面插入相比,只有一個參數不同。不得不說,看到一個函數被IE 4以上所有的瀏覽器都支持的時候,作為一個前端開發人員我還是挺驚訝的 _
作為子元素插入
假設我們已經有了如下HTML結構:
<div id="parent">
<div id="oldChild"></div>
</div>
現在我們希望在 parent 容器的第一個子元素之前插入一個新的 div 元素,就象這樣:
<div id="parent">
<div id="newChild"></div>
<div id="oldChild"></div>
</div>
jQuery
$('#parent').prepend('<div id="newChild"></div>');
DOM API
// IE 4+
document.getElementById('parent')
.insertAdjacentHTML('afterbegin', '<div id="newChild"></div>');
如果我們希望在第一個子元素的后面插入那個 div 元素,期望得到這樣的結構:
<div id="parent">
<div id="oldChild"></div>
<div id="newChild"></div>
</div>
jQuery
$('#parent').append('<div id="newChild"></div>');
DOM API
// IE 4+
document.getElementById('parent')
.insertAdjacentHTML('beforeend', '<div id="newChild"></div>');
這一節看上去和上一節差不多,總之我們發現使用DOM API操作元素也不是很復雜,而且到目前為止對瀏覽器的兼容性都很不錯,包括古老的IE瀏覽器也能很好的適應。
移動元素
假設有以下HTML結構:
<div id="parent">
<div id="c1"></div>
<div id="c2"></div>
<div id="c3"></div>
</div>
<div id="orphan"></div>
在這里希望把 #orphan 移動到 parent 容器中作為最后一個元素,期望的HTML是:
<div id="parent">
<div id="c1"></div>
<div id="c2"></div>
<div id="c3"></div>
<div id="orphan"></div>
</div>
jQuery
$('#parent').append($('#orphan'));
DOM API
// IE 5.5+
document.getElementById('parent')
.appendChild(document.getElementById('orphan'));
也還是蠻好記的對不對?如果我們希望把 #orphan 移動到 parent 容器的第一個元素,類似於:
<div id="parent">
<div id="orphan"></div>
<div id="c1"></div>
<div id="c2"></div>
<div id="c3"></div>
</div>
jQuery
$('#parent').prepend($('#orphan'));
DOM API
// IE 5.5+
document.getElementById('parent')
.insertBefore(document.getElementById('orphan'), document.getElementById('c1'));
直接使用DOM API看上去確實很長,這都是拜 document.getElementById 所賜。
刪除元素
假設我們的HTML元素中有一個 id="foobar" 的元素,我們希望把他從DOM樹中刪除:
jQuery
$('#foobar').remove();
DOM API
// IE 5.5+
document.getElementById('foobar')
.parentNode.removeChild(document.getElementById('foobar'));
添加/刪除 CSS Classes
假設在HTML中有這樣一個 div :
<div id="foo"></div>
我們希望給他加入名為 bold 的CSS Class,期望DOM變成這樣:
<div id="foo" class="bold"></div>
jQuery
$('#foo').addClass('bold');
DOM API
document.getElementById('foo').className += 'bold';
當然我們還可以把剛剛加上的Class刪除掉:
jQuery
$('#foo').removeClass('bold');
DOM API
// IE 5.5+
document.getElementById('foo').className =
document.getElementById('foo').className.replace(/^bold$/, '');
添加/刪除/修改元素屬性
仍然從簡單的 foo 元素開始:
<div id="foo"></div>
我們希望在 div 元素上設定 role="button" 來讓它能夠充當一個 button,這樣能夠在可訪問性設備(屏幕閱讀器等)上獲得較好的可訪問性:
jQuery
$('#foo').attr('role', 'button');
DOM API
// IE 5.5+
document.getElementById('foo').setAttribute('role', 'button');
這兩種方法都可以識別元素是否已經具備了這個屬性,然后自動創建/更新這個屬性。現在讓我們再把這個 role 刪除掉(我都覺得自己好煩…)
jQuery
$('#foo').removeAttr('role');
DOM API
// IE 5.5+
document.getElementById('foo').removeAttribute('role');
添加/修改內容
這次的 foo 元素比原來復雜多了(_):
<div id="foo">Hi there!</div>
如果要把 foo 的內容改成 Goodbye!:
jQuery
$('#foo').text('Goodbye!');
DOM API
// IE 5.5+
document.getElementById('foo').innerHTML = 'Goodbye!';
// IE 5.5+ but NOT Firefox
document.getElementById('foo').innerText = 'GoodBye!';
// IE 9+
document.getElementById('foo').textContent = 'Goodbye!';
最常見的 innerHTML 屬性在各種條件下都工作的很好。但是 innerText 和 textContent 的好處在於他們只是處理目標元素內的文字,而不是像 innerHTML 一樣直接插入標簽。當插入的內容是用戶輸入的內容時,這樣能夠一定程度上避免注入的問題。
添加/修改 Style
一般來說,直接用JavaScript腳本操作DOM元素的 style 是代碼中的“壞味道”,當然就像 goto 一樣我們總會有些時候需要這樣做。
假設HTML的結構是這樣的:
<span id="note">Attention!</span>
可以通過JavaScript代碼讓這段文字變得醒目一些,比如變成粗體(或者閃爍三下/轉體三圈):
jQuery
$('#note').css('fontWeight', 'bold');
DOM API
// IE 5.5+
document.getElementById('note').style.fontWeight = 'bold';
這里很難得我比較喜歡DOM API寫法,style.fontWeight 看上去比較像是正常的對象-屬性的邏輯。
專用的DOM操作庫
看到這里比上一篇[選擇元素]({% post_url /you-dont-need-jquery/2014-12-21-selector %}/)要容易一些,在IE 6及以上的版本中跨瀏覽器使用DOM API操作元素相對比較容易。jQuery確實使得冗長的DOM API變得簡單易懂,但是如果只是把jQuery用作DOM操作,似乎還是有些大材小用。我們可以試試jBone和dom.js這兩個庫,他們都可以在跨瀏覽器的情況下很好的兼容DOM元素操作,著名的Backbone中使用的正是前者。很多使用jQuery的開發人員覺得原生的DOM API不堪入目,但是我想他們並不真的掌握DOM API,其實DOM API並沒有比jQuery復雜太多。
如果我有漏掉什么重要的DOM元素操作,請在評論中告訴我。