這可能是最被忽略的文檔操作之一,這都怪微軟的不作為與W3C的無能,搞到大家只知道appendChild與insertBefore。後來爆出appendChild在IE有bug,好了,以後只用insertBefore了。現在jQuery興起後,無數趕鴨子上架的javascript素人連基本API也不學了,直接上手append, preppend, before, after與replaceWith,這比較悲哀……好了,我們先來看w3c的替換節點方法吧。
replacedNode = parentNode.replaceChild(newChild, oldChild)。從公式中我們可以看出科學家與工程師亽區別,為了執行它,需要三個節點進行參與,並且返回的是被替換的元素,這不利於鏈式操作。好處是適用性廣,支援XML與HTML。
var $ = function(id){ return document.getElementById(id) } var replace = function(){ var ul = $("ul"), lis = ul.innerHTML, ol = document.createElement("ol"); ul.parentNode.replaceChild(ol,ul); ol.innerHTML = lis; replace = function(){}//只允許執行一次 }
<br /><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>替換節點 by 司徒正美 </title><br /> <script type="text/javascript"><br /> var $ = function(id){<br /> return document.getElementById(id)<br /> }<br /> var replace = function(){<br /> var ul = $("ul"),<br /> lis = ul.innerHTML,<br /> ol = document.createElement("ol");<br /> ul.parentNode.replaceChild(ol,ul);<br /> ol.innerHTML = lis;<br /> replace = function(){}//只允許執行一次<br /> }</p><p> </script><br /> </head><br /> <body><br /> <ul id="ul" ><br /> <li>List Item 1</li><br /> <li>List Item 2</li><br /> <li>List Item 3</li><br /> <li>List Item 4</li><br /> </ul><br /> <button type="button" onclick = "replace()" >替換節點</button><br /> </body><br /></html><br />
運行代碼
oReplace = object.replaceNode(oNewNode)。微軟的私人實現,不過只支援HTML。好處是只用到兩個節點。
var $ = function(id){ return document.getElementById(id) } var replace = function(){ var ul = $("ul"), lis = ul.innerHTML, ol = document.createElement("ol"); ul.replaceNode(ol); ol.innerHTML = lis; }
<br /><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>替換節點 by 司徒正美 </title><br /> <script type="text/javascript"><br /> var $ = function(id){<br /> return document.getElementById(id)<br /> }<br /> var replace = function(){<br /> var ul = $("ul"),<br /> lis = ul.innerHTML,<br /> ol = document.createElement("ol");<br /> ul.replaceNode(ol);<br /> ol.innerHTML = lis;<br /> }</p><p> </script><br /> </head><br /> <body><br /> <ul id="ul" ><br /> <li>List Item 1</li><br /> <li>List Item 2</li><br /> <li>List Item 3</li><br /> <li>List Item 4</li><br /> </ul><br /> <button type="button" onclick = "replace()" >替換節點</button><br /> </body><br /></html><br />
運行代碼
outerHTML方式。非常高效的方式。不用建立節點,不過缺陷也比較多。先說IE,它的XML文檔不支援這方法,在HTML中,由於col, colgroup, frameset, html, head, style, title, table, tbody, tfoot, thead, tr, td與th的innerHTML是唯讀,因此修改它們時需要用到一些技巧。html,head,title也不說了,基本上操作文檔與它不沾邊。style元素也用得少,只要是table系列的。修改它們時,找到它們的table一併修改就是。標準瀏覽器方面,XML不支援,HTML則由於已列入草案,就剩下Firefox在負隅頑抗。如果我們要替換的元素有子節點而我們又需要保留它們,這時我們又得考慮這些元素在innerHTML之後的屬性恢複問題。參見我的另一篇博文《如何區分屬性與特性》,標準瀏覽器中不用setAttribute設定的屬性,會innerHTML中會丟失。因此我們這就要規範人們要用setAttribute設定屬性(特性),不要用obj.prop這種純javascript Object方式。
var $ = function(id){ return document.getElementById(id) } var replace = function(){ var ul = $("ul"); ul.outerHTML = "<ol>"+ul.innerHTML+"</ol>" replace = function(){}//只允許執行一次 }
<br /><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>替換節點 by 司徒正美 </title><br /> <script type="text/javascript"><br /> var $ = function(id){<br /> return document.getElementById(id)<br /> }<br /> var replace = function(){<br /> var ul = $("ul");<br /> ul.outerHTML = "<ol>"+ul.innerHTML+"</ol>"<br /> replace = function(){}//只允許執行一次<br /> }<br /> </script><br /> </head><br /> <body><br /> <ul id="ul" ><br /> <li>List Item 1</li><br /> <li>List Item 2</li><br /> <li>List Item 3</li><br /> <li>List Item 4</li><br /> </ul><br /> <button type="button" onclick = "replace()" >替換節點</button><br /> </body><br /></html><br />
運行代碼
下面是示範outerHTML在IE表格中遭遇滑鐵盧。
var replace = function(){ var td = $("td"); td.outerHTML = ""+td.innerHTML+"" replace = function(){}//只允許執行一次 }
<br /><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>替換節點 by 司徒正美 </title><br /> <script type="text/javascript"><br /> var $ = function(id){<br /> return document.getElementById(id)<br /> }<br /> var replace = function(){<br /> var td = $("td");<br /> td.outerHTML = "<th>"+td.innerHTML+"</th>"<br /> replace = function(){}//只允許執行一次<br /> }<br /> </script><br /> </head><br /> <body><br /> <table border="1"><br /> <tr><td id="td">Ruby Louvre</td></tr><br /> </table><br /> <button type="button" onclick = "replace()" >替換節點</button><br /> </body><br /></html><br />
運行代碼
修正方法:
var $ = function(id){ return document.getElementById(id) } var getTable = function(el){ while(el = el.parentNode){ if(el.tagName.toLowerCase() === "table") return el } } var tableObject = { "col":1, "colgroup":1, "tbody":1, "tfoot":1, "thead":1, "tr":1, "td":1, "th":1 }//frameset是HTML5要廢棄的元素,不管, html, head, title與style出現機率效少,也不管 var replace = function(){ var td = $("td"); if(!+"\v1" && tableObject[td.tagName.toLowerCase()]){ var table = getTable(td); table.outerHTML = table.outerHTML.replace(td.outerHTML,""+td.innerHTML+"") }else{ td.outerHTML = ""+td.innerHTML+"" } replace = function(){}//只允許執行一次 }
<br /><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <title>替換節點 by 司徒正美 </title><br /> <script type="text/javascript"><br /> var $ = function(id){<br /> return document.getElementById(id)<br /> }<br /> var getTable = function(el){<br /> while(el = el.parentNode){<br /> if(el.tagName.toLowerCase() === "table")<br /> return el<br /> }<br /> }<br /> var tableObject = {<br /> "col":1,<br /> "colgroup":1,<br /> "tbody":1,<br /> "tfoot":1,<br /> "thead":1,<br /> "tr":1,<br /> "td":1,<br /> "th":1<br /> }//frameset是HTML5要廢棄的元素,不管, html, head, title與style出現機率效少,也不管<br /> var replace = function(){<br /> var td = $("td");<br /> if(!+"\v1" && tableObject[td.tagName.toLowerCase()]){<br /> var table = getTable(td);<br /> table.outerHTML = table.outerHTML.replace(td.outerHTML,"<th>"+td.innerHTML+"</th>")<br /> }else{<br /> td.outerHTML = "<td>"+td.innerHTML+"</td>"<br /> }<br /> replace = function(){}//只允許執行一次<br /> }</p><p> </script><br /> </head><br /> <body><br /> <table border="1"><br /> <tr><th id="td">Ruby Louvre</th></tr><br /> </table><br /> <button type="button" onclick = "replace()" >替換節點</button><br /> </body><br /></html><br />
運行代碼
總結:以上例子的需求比較變態,都是限定要替換某一節點卻不替換它的子節點,如果不考慮其子節點,就方便多。為了效率,我們建議IE用replaceNode,Firefox用replaceChild,其他標準瀏覽器用outerHTML,我們可以把它們封裝為一個函數。至於為什麼不用innerHTML,好問題,因為要替換的節點可能存在兄弟節點。