JavaScript 語法 流程控制 Function (函數) Object (物件) 數值 布林值 字串 陣列 時間和日期 Math 物件
正規表示式 瀏覽器物件模型 BOM JS DOM HTML DOM CSS樣式 & Event

JavaScript DOM (Document Object Model)

JavaScript DOM (Document Object Model)

JavaScript 對 HTML文件做操作。
DOM (Document Object Model) 定義了一組標準 API (Application Programming Interface) 讓我們可以用 JavaScript 對 HTML文件做操作。
    API (HTML 網頁) = DOM + JavaScript。
文件物件模型(Document Object Model),它是一個網頁的程式介面,提供了一個樹狀結構的表示方法。
在DOM的樹狀結構中,DOM所管理的每一個資料都是一個節點(Node),而每一個節點皆為物件(Object)且擁有各自的 屬性 以及 方法,
而我們也可以透過DOM 屬性 與 方法 去改變網頁架構、風格和內容。
DOM 將一份 HTML 文件看作是一個樹狀結構的物件,讓我們可以方便直觀的存取樹中的節點 (node) 來改變其結構、樣式 (CSS) 或內容等。
HTML DOM 規範中定義了這些類型的 API:
我們可對 HTML的元素(element) 當作是JavaScript物件(object)來操作
定義了 HTML 元素有哪些 屬性(properties) 可以來做存取
定義了 HTML 元素有哪些 方法(methods) 可以來被操作
定義了 HTML 元素 事件(events),可以針對特定元素來綁定事件處理函式
      (例如使用者按下滑鼠、在鍵盤打字都是所謂的事件)
DOM 標準是由 W3C DOM 和 WHATWG DOM 組織來制定。
DOM API 的使用範例
 var paragraphs = document.getElementsByTagName('p');
      // getElementsByTagName 取得頁面上所有的 <p>元素
 for (var i=0; i < paragraphs.length; ++i) {
     paragraphs[i].style.color = 'green';
 }    // 將所有的 <p> 元素的文字顏色都改成綠色
       如右圖︰● Document 本身就是一個document node
              ● 所有的HTML elements也都是element nodes
              ● 所有的HTML attributes也都是attribute nodes
              ● 在HTML element內的text內容也是text node
              ● 所有的comments也都是comment nodes
更多 HTML DOM API 的使用方法,請看接下來章節的介紹:
  DOM 查找元素 : getElementById  getElementsByTagName  getElementByName  getElementByClassName
  DOM 節點屬性
  DOM 節點操作
  DOM HTML 屬性
  DOM CSS
  DOM 事件處理
 你也可以使用 jQuery library 來更方便的操作 DOM 和處理跨瀏覽器相容性問題 (cross-browser)。

JavaScript DOM 查找元素

document 物件是 DOM tree 的根節點,表示整份 HTML 文件,通常你要存取 HTML 都是從 document 物件開始。

document.getElementById('id')   根據 標籤的 id 取得一個 HTML 元素。

例如這一個 HTML 頁面:
<html>
<head>
  <title>取得一個 HTML 元素</title>
</head>
<body>
  <div id="container">
    <p id="para"> Some text here </p>
  </div>
 <input id="xx" type="text" value="Hello World">
</body>
</html>

  我們可以如下取得其中 id 為 para 的 p 元素:
  var elem = document.getElementById('para');
使用document.getElementById("para")取得 id為para的 HTML element:
document.getElementById('para').innerHTML 屬性
  取得id為 para的 p 標籤下所有的內容。       // Some text here
document.getElementById('container').innerHTML 屬性
  取得id為 container的 div 標籤下所有的 HTML內容。
  	                 // <p id="para"> Some text here </p>
document.getElementById('container').innerText 屬性
  取得id為 container的 div 標籤下的文字內容。 // Some text here
  innerText屬性和innerHTML用法類似,只是innerText 會將HTML標籤去除
document.getElementById('container').textContent 屬性
  取得id為 container的 div 標籤下的文字內容。 // Some text here
  textContent 屬性和 innerText 用法類似,但有以下這些差異:
  innerText不會返回畫面中看不見的元素(例如樣式是visibility:hidden;
    或 display:none;),但 textContent 會返回。
document.getElementById('xx').value 屬性
  取得id為 xx 的 input標籤下的 value屬性內容。 // Hello World

Some text here

input標籤 id="xx" value=

取得 id為 para的 p標籤(innerHTML):
div標籤(textContent):, div標籤(innerHTML):
div標籤(innerText):
input標籤下的 value屬性內容 :

document.getElementsByTagName('name')   根據HTML 標籤 (tag)名稱 取得所有這個標籤的元素集合,返回的結果是一個陣列(array)物件。

每個 HTML DOM 元素也有 getElementsByTagName 方法 - node.getElementsByTagName(name),用來找該元素下面的子元素。
例如這一個 HTML 頁面:
<html>
<head>
<title>取得標籤名稱的元素</title>
</head>
<body>
  <p> P111 text </p>
  <p> P222 text </p>     
  <div id="div1">
    <p> div1a text </p>
    <p> div1b text </p>
    <p> div1c text </p>   
    <div id="div2">
      <p> div2x text </p>
      <p> div2y text </p>
    </div>
  </div>
  <p> P333 text </p>
  <p> P444 text </p>
</body>
</html>
我們可以用 JavaScript 這樣存取 HTML 元素:
function getAllParaElems() {
    var allParas = document.getElementsByTagName('p');     // 取得所有的 <p> 元素
    var num = allParas.length;                // 總共有幾個 <p>元素   // num = 9
    // .....
}

function div1ParaElems() {
    var div1 = document.getElementById('div1');     // 取得 id 為 div1 的 HTML元素
    var div1Paras = div1.getElementsByTagName('p');   // 取得 div1下面所有的<p>元素
    var num = div1Paras.length;          // div1 下面總共有幾個 <p>元素 // num = 5
    // .....
}

function div2ParaElems() {
    var div2 = document.getElementById('div2');     // 取得 id 為 div2 的 HTML元素
    var div2Paras = div2.getElementsByTagName('p');   //取得 div2下面所有的 <p>元素
    var num = div2Paras.length;          // div2 下面總共有幾個 <p>元素 // num = 2
    // .....
}

document.getElementsByName('name')   根據 標籤的 特定名稱(name) 的 HTML 元素集合,返回的結果是一個陣列(array)物件。

例如這一個 HTML 頁面:
<html>
<head>
  <title>取得 標籤有特定名稱(name) 的元素</title>
</head>
<body>
  <form name="up"><input type="text"></form>
  <div name="down"><input type="text"></div>
</body>
</html>
  我們可以用 JavaScript 這樣存取有 特定名稱(name) 的HTML 元素:
  var upForms = document.getElementsByName('up');      // 取得 name 是 up 的元素
  console.log(upForms[0].tagName);                     // 輸出 "FORM"     第一個 標籤(tag)名稱name='up'的tagName

document.getElementsByClassName('names')   取得特定類別名稱 (class name) 的HTML元素集合,返回的結果是一個陣列(array)物件。

每個 HTML DOM 元素也有 getElementsByClassName 方法 - node.getElementsByClassName(names),用來找該元素下面的子元素。
Node.childNodes
所有的 DOM 節點物件都有 childNodes 屬性 (read-only property),可以用來取得該元素下的所有子元素集合 (NodeList)。
Node.children
DOM 節點物件的 children 屬性和 childNodes 屬性類似,差異在於 childNodes 返回的子元素會包含文字節點(text nodes) 和註解節點(comment nodes),
children 屬性則只會返回 HTML 元素節點 (HTMLCollection)。
Node.firstChild
DOM 節點物件的 firstChild 屬性可以用來取得其下的第一個子節點或返回 null 表示沒有任何子節點。
Node.lastChild
DOM 節點物件的 lastChild 屬性可以用來取得其下的最後一個子節點或返回 null 表示沒有任何子節點。
Node.parentNode
DOM 節點物件的 parentNode 屬性可以用來取得其父元素,得到值可能會是一個元素節點(Element node)、根節點(Document node) 或 DocumentFragment節點。
Node.previousSibling
DOM 節點物件的 previousSibling 屬性用來取得在目前節點前面的兄弟節點 (sibling),返回 null 表示該節點已經是第一個子節點。
Node.nextSibling
DOM 節點物件的 nextSibling 屬性用來取得在目前節點後面的兄弟節點 (sibling),返回 null 表示該節點已經是最後一個子節點。

JavaScript DOM Node Properties (DOM 節點物件的屬性)

Node.nodeType

nodeType屬性 可以取得該節點的類型,像是elements (元素節點), text (文字節點)或 comments (註解節點)。
另外 DOM 還有這些常數 (Node type constants),幫助你來判斷節點類型:
常數名稱 說明
Node.ELEMENT_NODE 1 表示 HTML 元素 (Element) 節點,像是 <p> 或 <div>
Node.TEXT_NODE 3 表示文字 (Text) 或屬性 (Attr) 節點
Node.COMMENT_NODE 8 表示註解節點 (Comment)
Node.DOCUMENT_NODE 9 表示根節點 (Document)
Node.DOCUMENT_TYPE_NODE 10 表示 DocumentType 節點,像是 <!DOCTYPE html>
Node.DOCUMENT_FRAGMENT_NODE 11 表示 DocumentFragment 節點
使用範例:
document.nodeType === Node.DOCUMENT_NODE;                  // true
document.doctype.nodeType === Node.DOCUMENT_TYPE_NODE;     // true
var p = document.createElement('p');
p.textContent = 'Once upon a time...';
p.nodeType === Node.ELEMENT_NODE;                // true
p.firstChild.nodeType === Node.TEXT_NODE;        // true

Node.nodeName

nodeName屬性 會返回節點的名稱。
節點類型 nodeName 的值
Attr 值同 Attr.name
Comment "#comment"
Document "#document"
DocumentFragment "#document-fragment"
DocumentType 值同 DocumentType.name,例如 "html"
Element 值同 Element.tagName
Text "#text"
例子:
<div id="d1"> hello world </div>
<input id="t" type="text">
<script>
    var div = document.getElementById('d1');
    var ttt = document.getElementById('t');
    alert(div.nodeName);           // 顯示 "DIV"
    alert(ttt.nodeName);          // 顯示 "INPUT"
</script>
nodeName 返回的 HTML 元素節點名稱都是大寫的英文字 (upper case);
但如果你的頁面模式是 XML-mode 則會返回原本標籤的大小寫不變。

Element.tagName

tagName 和 nodeName 基本上是一樣了,除了 tagName 屬性只有 HTML 元素節點才有,在其他類型的節點 (例如 text nodes) 值則會是 undefined。

Node.nodeValue

nodeValue 屬性用來取得 text, comment 和 CDATA 節點的內容,如果是 attribute 節點則會返回屬性內容。
例如:
<div id="foo"> hello world </div>
<script>
    var div = document.getElementById('foo');
    alert(div.firstChild.nodeValue);           // 顯示 hello world
    alert(div.attributes.id.nodeValue);          // 顯示 foo
</script>

Element.innerHTML

innerHTML 屬性可以用來取得一個 DOM 元素節點中的 HTML 內容。
用法:
<div id="foo"> <span> hello world </span> 101 </div>
<script>
    var div = document.getElementById('foo');
    alert(div.innerHTML);           // 顯示 <span> hello world </span> 101
</script>
innerHTML 屬性是可寫的,可以用來改變某元素下的 HTML 內容:
<script>
    var div = document.getElementById('foo');
    div.innerHTML = '123';       // 將 div 的內容改成 123
    alert(div.innerHTML);        // 顯示 123   // div.innerHTML 等同於 document.getElementById('foo').innerHTML
</script>

Element.innerText

innerText 屬性和 innerHTML 用法類似,只是 innerText 會將 HTML 標籤去除。
例如:
<div id="foo"> <span> hello world </span> 101 </div>
<script>
    var div = document.getElementById('foo');
    alert(div.innerText);           // 顯示 hello world 101
</script>
innerText 也可以用來寫入內容,但它會將 HTML 特殊符號自動轉成 HTML Entity:
<script>
    var div = document.getElementById('foo');
    div.innerText = '<span> one </span><span> two </span>';    // 將 div 的內容改成 one two
    alert(div.innerHTML);     // 顯示 & lt; span & gt; one & lt; /span & gt; & lt; span & gt; two & lt; /span & gt;
</script>

Node.textContent

textContent 屬性和 innerText 用法類似,但有下面這些差異:
textContent 會返回包含 <script> 和 <style> 的所有內容,但 innerText 不會。
innerText 不會返回畫面中看不見的元素 (例如樣式是 visibility: hidden; 或 display: none;),但 textContent 會返回。
另外由於 textContent 或 innerText 都會將 HTML 特殊符號自動轉成 HTML Entity 的特性,很適合用來防止 XSS 安全漏洞攻擊。
IE 在 IE9 開始才有支援 textContent。

Element.outerHTML

outerHTML 屬性可以用來取得一個 DOM 元素節點的 HTML 內容,跟 innerHTML 的差別在於 outerHTML 還會返回節點本身的 HTML 內容。
例如:
<div id="foo"> <span> hello world </span> 101 </div>
<script>
    var div = document.getElementById('foo');
    alert(div.outerHTML);           // 顯示 <div id="foo"><span>hello world</span>101</div>
</script>
outerHTML 屬性還可以用來改變某元素的 HTML 內容,有點像取代掉原節點的意思:
<div id="container"> <div id="foo"> foo </div></div>
<script>
    var div = document.getElementById('foo');
    div.outerHTML = '<div id="bar">bar</div>';   // 將原節點用新的 HTML 取代
    alert(document.getElementById('container').outerHTML);   // 顯示 <div id="container"><div id="bar">bar</div></div>
</script>

DOM 節點操作 JavaScript DOM Manipulating (新增、修改、刪除 DOM 節點)

除了提過的 innerHTML, innerText, textContent 和 outerHTML 可以用來改變 DOM 的結構和內容之外,
我們在下面文章會中介紹其他 新增、修改 和 刪除 DOM 節點的方法。

document.createElement(tagName)

方法用來建立一個新的 HTML 元素。

document.createTextNode(str)

方法用來建立一個新的 文字節點 (text node)。

ParentNode.appendChild(aChild)

DOM 節點的.appendChild() 方法 用來新增一個新的子元素到現有子元素的最後面。

ParentNode.insertBefore(newNode, referenceNode)

DOM 節點的.insertBefore(newNode, referenceNode)方法 用來將一個新的元素加到某個元素的前面。

ParentNode.removeChild(child)

.removeChild(child) 方法用來移除 DOM 節點。

ParentNode.replaceChild(newChild, oldChild)

.replaceChild(newChild, oldChild) 方法用新節點來取代某個子節點, 這個新節點可以是某個已存在的節點或是新節點。

Node.cloneNode(deep)

.cloneNode(deep) 方法可以用來複製一個節點,cloneNode 預設不會複製節點的內容, 你可以傳入參數 true 來複製節點的內容。

document.write(html)

document.write 可以用來在頁面載入的時候,將 HTML 內容寫入頁面中。

JavaScript DOM HTML 屬性 (HTML Attributes) -- DOM Properties   &   HTML Attributes

DOM 中的 Properties 和 Attributes 中文都稱作屬性,但差別在哪?
     Properties 是 JavaScript DOM 物件上的屬性,不會影響到HTML元素;
Attributes 是 HTML元素上的屬性,像是 HTML 標籤上的 id 或 class 屬性。
我們將會來介紹怎麼透過 DOM API 操作 HTML 上的元素屬性。

Element.hasAttribute('attrName')

hasAttribute 方法用來檢查 HTML 元素是否有某個屬性。
例如:
<a id="foo" href="http://www.fooish.com/"> www.fooish.com </a>
<script>
  var foo = document.getElementById('foo'); // 取得目前頁面上的 foo元素
      alert(foo.hasAttribute('xyz'));       // 顯示 false
      alert(foo.hasAttribute('href'));      // 顯示 true
</script>

Element.getAttribute('attrName')

getAttribute 方法用來取得 HTML 元素的屬性值 - 一個字串,或返回 null 如果沒有這個屬性。
例如:
<a id="foo" href="http://www.fooish.com/" target="_blank" data-foo> www.fooish.com </a>
<script>
  var foo = document.getElementById('foo');  // 取得目前頁面上的 foo元素
      alert(foo.getAttribute('xyz'));        // 顯示 null
      alert(foo.getAttribute('href'));       // 顯示 http://www.fooish.com/
      alert(foo.getAttribute('target'));     // 顯示 _blank
      alert(foo.getAttribute('data-foo'));   // 顯示 "" 空字串
</script>

Element.setAttribute('attrName, value')

setAttribute 方法用來新增 HTML 元素的屬性,如果屬性已經存在則更新其值。
例如:
<a id="foo" href="http://www.fooish.com/"> www.fooish.com </a>
<script>
  var foo = document.getElementById('foo');     // 取得目前頁面上的 foo元素
      alert(foo.getAttribute('target'));        // 顯示 null
      foo.setAttribute('target', '_blank');     // 將 target 屬性設定為  _blank
      alert(foo.getAttribute('target'));        // 顯示 _blank
</script>

Element.removeAttribute('attrName')

removeAttribute 方法用來移除 HTML 元素的某個屬性。
例如:
<a id="foo" href="http://www.fooish.com/" data-foo="101"> www.fooish.com </a>
<script>
  var foo = document.getElementById('foo');       // 取得目前頁面上的 foo元素
      alert(foo.getAttribute('data-foo'));        // 顯示 101
      foo.removeAttribute('data-foo');            // 將 data-foo 屬性 移除
      alert(foo.getAttribute('data-foo'));        // 顯示 null
</script>

Element.attributes

DOM 元素的 attributes 屬性 (property) 可以取得 HTML 元素上所有的屬性 (attributes),attributes 會返回一個 key / value    pair 的 NamedNodeMap 型態物件。
NamedNodeMap 物件的 key 是一個字串表示屬性名稱,value 則是一個 Attr 物件,Attr 物件上的 name 屬性可以取得屬性名稱,Attr 物件上的 value 屬性可以取得屬性值。
例如:
<a id="foo" href="http://www.fooish.com/"> www.fooish.com </a>
<script>
  var foo = document.getElementById('foo');     // 取得目前頁面上的 foo元素
      alert(foo.attributes['href'].name);       // 顯示 href
      alert(foo.attributes['href'].value);      // 顯示 http://www.fooish.com/
</script>

你可以用 for 迴圈遍歷所有的屬性:
<a id="foo" href="http://www.fooish.com/"> www.fooish.com </a>
<script>
  var foo = document.getElementById('foo');                      // 取得目前頁面上的 foo元素
  var attr;
  for (var i=0; i < foo.attributes.length; ++i) {
       attr = foo.attributes[i];                                 // 依序會輸出:
       console.log(attr.name + ': ' + attr.value);               // id: foo
      }                                                          // href: http://www.fooish.com/
</script>

HTML Attributes 對應的 DOM Properties

DOM 元素物件上有不同類型的 Properties 直接對應到相關的 HTML Attributes,讓你方便讀寫 HTML 屬性,
通常 DOM Properties 和 HTML Attributes 是同樣的名稱。
以下舉幾個例子:

id

DOM 元素的 id 屬性對應 HTML 上的 id 屬性。
例如:
<div id="container"><span id="foo">101</span></div>
<script>
  var foo = document.getElementById('foo');                   // 取得目前頁面上的 foo元素
      alert(foo.id);                                          // 顯示 foo
      foo.id = 'bar';                                         // 將 id 改成 bar
      alert(document.getElementById('container').innerHTML);  // 顯示 <span id="bar">101</span>
</script>

className

className property 對應到 HTML class 屬性,名稱不同是一個特例,因為 class 是 JavaScript 中的保留字 (reserved word)。
例如:
<span id="foo" class="foo bar">101</span>
<script>
  var foo = document.getElementById('foo');                   // 取得目前頁面上的 foo元素
      alert(foo.className);                                   // 顯示 foo bar
</script>

href

href 可以用來讀寫 <a> 連結元素的 href 屬性:
<a id="foo">fooish</a>
<script>
  var foo = document.getElementById('foo');        // 取得目前頁面上的 foo元素
      alert(foo.href);                             // 顯示 "" 空字串
      foo.href = 'http://www.fooish.com/';
      alert(foo.outerHTML);                        // 顯示 <a id="foo" href="http://www.fooish.com/">fooish</a>
</script>