首頁 >web前端 >js教程 >JavaScript常見原生DOM操作API總結

JavaScript常見原生DOM操作API總結

黄舟
黄舟原創
2017-02-21 11:51:351190瀏覽



最近面試的時候被這個問題給卡片了,所以抽時間好好複習一下。

幾個物件

Node

#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

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

HTMLCollection是一個特殊的NodeList,表示包含了若干元素(元素順序為文檔流中的順序)的通用集合,它是即時更新的,當其所包含的元素改變時,它會自動更新。另外,它是一個偽數組,如果想像數組一樣操作它們需要像 Array.prototype.slice.call(nodeList, 2) 這樣呼叫。

節點查找API

  • 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;

節點建立API

##節點建立API主要包括createElement 、 createTextNode 、 cloneNode 和createDocumentFragment 四個方法。

createElement

建立元素:

var elem = document.createElement("p");
elem.id = 'test';
elem.style = 'color: red';
elem.innerHTML = '我是新创建的节点';
document.body.appendChild(elem);

透過createElement 建立的元素並不屬於document 對象,它只是建立出來,並未新增到html文件中,若要呼叫appendChild 或insertBefore 等方法將其新增至HTML文件中。

createTextNode

建立文字節點:
    var node = document.createTextNode("我是文本节点");
    document.body.appendChild(node);
  1. cloneNode

  2. 複製一個節點: node.cloneNode (true/false) ,它接收一個bool參數,用來表示是否複製子元素。

    var from = document.getElementById("test");
    var clone = from.cloneNode(true);
    clone.id = "test2";
    document.body.appendChild(clone);

    克隆節點並不會複製事件,除非事件是用7c44e228916a0ba857090b7d794510e094b3e26ee717c64999d7867364b1b4a3 這種方式綁定的,用addEventListener 和node.onclick= xxx; 方式綁定的都不會複製。

createDocumentFragment

本方法用來建立一個DocumentFragment ,也就是文檔碎片,它表示一種輕量級的文檔,主要是用來儲存臨時節點,大量操作DOM時用它可以大大提升效能。

假設現有一題目,要求給ul添加10000個li,我們先用最簡單的拼接字符串的方式來實現:

<ul id="ul"></ul>
<script>
(function()
{
    var start = Date.now();
    var str = &#39;&#39;;
    for(var i=0; i<10000; i++) 
    {
        str += &#39;<li>第&#39;+i+&#39;个子节点</li>&#39;;
    }
    document.getElementById(&#39;ul&#39;).innerHTML = str;
    console.log(&#39;耗时:&#39;+(Date.now()-start)+&#39;毫秒&#39;); // 44毫秒
})();
</script>

再換逐個append的方式,不用說,這種方式效率肯定低:

<ul id="ul"></ul>
<script>
(function()
{
    var start = Date.now();
    var str = &#39;&#39;, li;
    var ul = document.getElementById(&#39;ul&#39;);
    for(var i=0; i<10000; i++)
    {
        li = document.createElement(&#39;li&#39;);
        li.textContent = &#39;第&#39;+i+&#39;个子节点&#39;;
        ul.appendChild(li);
    }
    console.log(&#39;耗时:&#39;+(Date.now()-start)+&#39;毫秒&#39;); // 82毫秒
})();
</script>
最後再試試文檔碎片的方法,可以預見的是,這種方式肯定比第二種好很多,但是應該沒有第一種快:
<ul id="ul"></ul>
<script>
(function()
{
    var start = Date.now();
    var str = &#39;&#39;, li;
    var ul = document.getElementById(&#39;ul&#39;);
    var fragment = document.createDocumentFragment();
    for(var i=0; i<10000; i++)
    {
        li = document.createElement(&#39;li&#39;);
        li.textContent = &#39;第&#39;+i+&#39;个子节点&#39;;
        fragment.appendChild(li);
    }
    ul.appendChild(fragment);
    console.log(&#39;耗时:&#39;+(Date.now()-start)+&#39;毫秒&#39;); // 63毫秒
})();
</script>

節點修改API

######節點修改API都具有以下這幾個特點:############不管是新增或取代節點,如果原本就在頁面上,那麼原來位置的節點將會被移除;############修改之後節點本身綁定的事件不會消失;######### #######appendChild#########這個其實前面已經多次用到了,文法就是:###
parent.appendChild(child);
###它會將child追加到parent的子節點的最後面。另外,如果被加入的節點是一個頁面中存在的節點,則執行後這個節點將會加入新的位置,其原本所在的位置將會移除該節點,也就是說不會同時存在兩個該節點在頁面上,且其事件會保留。 #########insertBefore#########將某個節點插入到另一個節點的前面,語法:###
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(&#39;click&#39;, function()
{
    var newNode = document.createElement("p");
    newNode.textContent = "我是新节点";
    parent.insertBefore(newNode, child);
}, false);
</script>

关于第二个参数:

  • refNode是必传的,如果不传该参数会报错;

  • 如果refNode是undefined或null,则insertBefore会将节点添加到末尾;

removeChild

removeChild用于删除指定的子节点并返回子节点,语法:

var deletedChild = parent.removeChild(node);

deletedChild指向被删除节点的引用,它仍然存在于内存中,可以对其进行下一步操作。另外,如果被删除的节点不是其子节点,则将会报错。一般删除节点都是这么删的:

function removeNode(node)
{
    if(!node) return;
    if(node.parentNode) node.parentNode.removeChild(node);
}

replaceChild

replaceChild用于将一个节点替换另一个节点,语法:

parent.replaceChild(newChild, oldChild);

节点关系API

DOM中的节点相互之间存在着各种各样的关系,如父子关系,兄弟关系等。

父关系API

  • parentNode :每个节点都有一个parentNode属性,它表示元素的父节点。Element的父节点可能是Element,Document或DocumentFragment;

  • parentElement :返回元素的父元素节点,与parentNode的区别在于,其父节点必须是一个Element元素,如果不是,则返回null;

子关系API

  • children :返回一个实时的 HTMLCollection ,子节点都是Element,IE9以下浏览器不支持;

  • childNodes :返回一个实时的 NodeList ,表示元素的子节点列表,注意子节点可能包含文本节点、注释节点等;

  • firstChild :返回第一个子节点,不存在返回null,与之相对应的还有一个 firstElementChild ;

  • lastChild :返回最后一个子节点,不存在返回null,与之相对应的还有一个 lastElementChild ;

兄弟关系型API

  • previousSibling :节点的前一个节点,如果不存在则返回null。注意有可能拿到的节点是文本节点或注释节点,与预期的不符,要进行处理一下。

  • nextSibling :节点的后一个节点,如果不存在则返回null。注意有可能拿到的节点是文本节点,与预期的不符,要进行处理一下。

  • previousElementSibling :返回前一个元素节点,前一个节点必须是Element,注意IE9以下浏览器不支持。

  • nextElementSibling :返回后一个元素节点,后一个节点必须是Element,注意IE9以下浏览器不支持。

元素属性型API

setAttribute

给元素设置属性:

element.setAttribute(name, value);

其中name是特性名,value是特性值。如果元素不包含该特性,则会创建该特性并赋值。

getAttribute

getAttribute返回指定的特性名相应的特性值,如果不存在,则返回null:

var value = element.getAttribute("id");

样式相关API

直接修改元素的样式

elem.style.color = &#39;red&#39;;
elem.style.setProperty(&#39;font-size&#39;, &#39;16px&#39;);
elem.style.removeProperty(&#39;color&#39;);

动态添加样式规则

var style = document.createElement(&#39;style&#39;);
style.innerHTML = &#39;body{color:red} #top:hover{background-color: red;color: white;}&#39;;
document.head.appendChild(style);

window.getComputedStyle

通过 element.sytle.xxx 只能获取到内联样式,借助 window.getComputedStyle 可以获取应用到元素上的所有样式,IE8或更低版本不支持此方法。

var style = window.getComputedStyle(element[, pseudoElt]);

getBoundingClientRect

getBoundingClientRect 用来返回元素的大小以及相对于浏览器可视窗口的位置,用法如下:

var clientRect = element.getBoundingClientRect();

clientRect是一个 DOMRect 对象,包含width、height、left、top、right、bottom,它是相对于窗口顶部而不是文档顶部,滚动页面时它们的值是会发生变化的。

JavaScript常見原生DOM操作API總結

 

以上就是JavaScript常见原生DOM操作API总结的内容,更多相关内容请关注PHP中文网(www.php.cn)!

 

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn