最近面試的時候被這個問題給卡片了,所以抽時間好好複習一下。
#Node是一個接口,中文叫節點,很多類型的DOM元素都是繼承於它,都共享著相同的基本屬性和方法。常見的Node有 element,text,attribute,comment,document 等(所以要注意 節點 和 元素 的區別,元素屬於節點的一種)。
Node有一個屬性nodeType 表示Node的類型,它是一個整數,其數值分別表示對應的Node類型,具體如下:
{ ELEMENT_NODE: 1, // 元素节点 ATTRIBUTE_NODE: 2, // 属性节点 TEXT_NODE: 3, // 文本节点 DATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, // 注释节点 DOCUMENT_NODE: 9, // 文档 DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, // 文档碎片 NOTATION_NODE: 12, DOCUMENT_POSITION_DISCONNECTED: 1, DOCUMENT_POSITION_PRECEDING: 2, DOCUMENT_POSITION_FOLLOWING: 4, DOCUMENT_POSITION_CONTAINS: 8, DOCUMENT_POSITION_CONTAINED_BY: 16, DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32 }
NodeList 物件是一個節點的集合,一般由Node.childNodes 、 document.getElementsByName 和document.querySelectorAll 傳回的。
不過需要注意, Node.childNodes 、 document.getElementsByName 傳回的 NodeList 的結果是即時的(此時跟HTMLCollection比較類似),而 document.querySelectorAll 傳回的結果是固定的,這一點比較特殊。
舉例如下:
var childNodes = document.body.childNodes; console.log(childNodes.length); // 如果假设结果是“2” document.body.appendChild(document.createElement('p')); console.log(childNodes.length); // 此时的输出是“3”
HTMLCollection是一個特殊的NodeList,表示包含了若干元素(元素順序為文檔流中的順序)的通用集合,它是即時更新的,當其所包含的元素改變時,它會自動更新。另外,它是一個偽數組,如果想像數組一樣操作它們需要像 Array.prototype.slice.call(nodeList, 2) 這樣呼叫。
document.getElementById :根據ID找出元素,大小寫敏感,如果有多個結果,只傳回第一個;
document.getElementsByClassName :根據類別名稱尋找元素,多個類別名稱以空格分隔,傳回一個HTMLCollection 。注意相容性為IE9+(含)。另外,不只是document,其它元素也支援 getElementsByClassName 方法;
document.getElementsByTagName :根據標籤尋找元素, * 表示查詢所有標籤,傳回一個 HTMLCollection 。
document.getElementsByName :根據元素的name屬性尋找,傳回一個 NodeList 。
document.querySelector :傳回單一Node,IE8+(含),如果符合到多個結果,只傳回第一個。
document.querySelectorAll :傳回一個 NodeList ,IE8+(含)。
document.forms :取得目前頁面所有form,回傳一個HTMLCollection;
createElement
建立元素:var elem = document.createElement("p"); elem.id = 'test'; elem.style = 'color: red'; elem.innerHTML = '我是新创建的节点'; document.body.appendChild(elem);
var node = document.createTextNode("我是文本节点"); document.body.appendChild(node);
cloneNode
var from = document.getElementById("test"); var clone = from.cloneNode(true); clone.id = "test2"; document.body.appendChild(clone);
<ul id="ul"></ul> <script> (function() { var start = Date.now(); var str = ''; for(var i=0; i<10000; i++) { str += '<li>第'+i+'个子节点</li>'; } document.getElementById('ul').innerHTML = str; console.log('耗时:'+(Date.now()-start)+'毫秒'); // 44毫秒 })(); </script>
<ul id="ul"></ul> <script> (function() { var start = Date.now(); var str = '', li; var ul = document.getElementById('ul'); for(var i=0; i<10000; i++) { li = document.createElement('li'); li.textContent = '第'+i+'个子节点'; ul.appendChild(li); } console.log('耗时:'+(Date.now()-start)+'毫秒'); // 82毫秒 })(); </script>
<ul id="ul"></ul> <script> (function() { var start = Date.now(); var str = '', li; var ul = document.getElementById('ul'); var fragment = document.createDocumentFragment(); for(var i=0; i<10000; i++) { li = document.createElement('li'); li.textContent = '第'+i+'个子节点'; fragment.appendChild(li); } ul.appendChild(fragment); console.log('耗时:'+(Date.now()-start)+'毫秒'); // 63毫秒 })(); </script>
節點修改API
######節點修改API都具有以下這幾個特點:############不管是新增或取代節點,如果原本就在頁面上,那麼原來位置的節點將會被移除;############修改之後節點本身綁定的事件不會消失;######### #######appendChild#########這個其實前面已經多次用到了,文法就是:###parent.appendChild(child);
parentNode.insertBefore(newNode, refNode);
这个API个人觉得设置的非常不合理,因为插入节点只需要知道newNode和refNode就可以了,parentNode是多余的,所以jQuery封装的API就比较好:
newNode.insertBefore(refNode); // 如 $("p").insertBefore("#foo");
所以切记不要把这个原生API和jQuery的API使用方法搞混了!为了加深理解,这里写一个简单的例子:
<p id="parent"> 我是父节点 <p id="child"> 我是旧的子节点 </p> </p> <input type="button" id="insertNode" value="插入节点" /> <script> var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.getElementById("insertNode").addEventListener('click', function() { var newNode = document.createElement("p"); newNode.textContent = "我是新节点"; parent.insertBefore(newNode, child); }, false); </script>
关于第二个参数:
refNode是必传的,如果不传该参数会报错;
如果refNode是undefined或null,则insertBefore会将节点添加到末尾;
removeChild用于删除指定的子节点并返回子节点,语法:
var deletedChild = parent.removeChild(node);
deletedChild指向被删除节点的引用,它仍然存在于内存中,可以对其进行下一步操作。另外,如果被删除的节点不是其子节点,则将会报错。一般删除节点都是这么删的:
function removeNode(node) { if(!node) return; if(node.parentNode) node.parentNode.removeChild(node); }
replaceChild用于将一个节点替换另一个节点,语法:
parent.replaceChild(newChild, oldChild);
DOM中的节点相互之间存在着各种各样的关系,如父子关系,兄弟关系等。
parentNode :每个节点都有一个parentNode属性,它表示元素的父节点。Element的父节点可能是Element,Document或DocumentFragment;
parentElement :返回元素的父元素节点,与parentNode的区别在于,其父节点必须是一个Element元素,如果不是,则返回null;
children :返回一个实时的 HTMLCollection ,子节点都是Element,IE9以下浏览器不支持;
childNodes :返回一个实时的 NodeList ,表示元素的子节点列表,注意子节点可能包含文本节点、注释节点等;
firstChild :返回第一个子节点,不存在返回null,与之相对应的还有一个 firstElementChild ;
lastChild :返回最后一个子节点,不存在返回null,与之相对应的还有一个 lastElementChild ;
previousSibling :节点的前一个节点,如果不存在则返回null。注意有可能拿到的节点是文本节点或注释节点,与预期的不符,要进行处理一下。
nextSibling :节点的后一个节点,如果不存在则返回null。注意有可能拿到的节点是文本节点,与预期的不符,要进行处理一下。
previousElementSibling :返回前一个元素节点,前一个节点必须是Element,注意IE9以下浏览器不支持。
nextElementSibling :返回后一个元素节点,后一个节点必须是Element,注意IE9以下浏览器不支持。
给元素设置属性:
element.setAttribute(name, value);
其中name是特性名,value是特性值。如果元素不包含该特性,则会创建该特性并赋值。
getAttribute返回指定的特性名相应的特性值,如果不存在,则返回null:
var value = element.getAttribute("id");
elem.style.color = 'red'; elem.style.setProperty('font-size', '16px'); elem.style.removeProperty('color');
var style = document.createElement('style'); style.innerHTML = 'body{color:red} #top:hover{background-color: red;color: white;}'; document.head.appendChild(style);
通过 element.sytle.xxx 只能获取到内联样式,借助 window.getComputedStyle 可以获取应用到元素上的所有样式,IE8或更低版本不支持此方法。
var style = window.getComputedStyle(element[, pseudoElt]);
getBoundingClientRect 用来返回元素的大小以及相对于浏览器可视窗口的位置,用法如下:
var clientRect = element.getBoundingClientRect();
clientRect是一个 DOMRect 对象,包含width、height、left、top、right、bottom,它是相对于窗口顶部而不是文档顶部,滚动页面时它们的值是会发生变化的。
以上就是JavaScript常见原生DOM操作API总结的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!