摘要MDN對DOM的定義:
The data representation of the objects that comprise the structure and content of a document on the web;
A programming interface for web documents;
The DOM represents the document as nodes and objects; that way, programming languages can interact with the page.
大意是說,DOM(Document Object Model)是瀏覽器對HTML文件(document)元素轉換成節點(node)和物件(object)的結構化表現,同時提供程式語言操作節點和物件的方法。
簡而言之就是,瀏覽器會將HTML元素和內容(包含文字與註解)轉換成程式語言可以操作的節點和物件,讓使用者可以跟HTML頁面互動。
HTMLCollection、NodeList
有些操作元素方法會將元素以 HTMLCollection
型別回傳,有些則將元素以 NodeList
型別回傳,這兩者的差異在於:
HTMLCollection
是 life collection,如果對HTML頁面元素作任何改變,會立刻反映在回傳的元素:例如原本要選取的元素有4個,直接在developor tools inspect 刪除一個要選取的元素標籤,則選取元素的HTMLCollcetion結果會變3個;- 相反地,
NodeList
不是life collection,若如上述刪除標籤不會讓回傳的NodeList
元素數量有任何改變;意即,除非JavaScript檔案已經寫好要執行那些事件才會刪除元素,否則使用者"直接對頁面元素作操控"都不會影響接下來瀏覽器選取元素的結果有任何改變,仍然是4個。
DOM Manipulation
以下筆記JavaScript操作DOM的一些常用方法:
Selection
/* Selection */
// 選取整個頁面
document.documentElement
// 選取 <head> 或 <body>
document.head
document.body
// 選取元素 (return NodeList)
document.querySelector(/* CSS selector */);
docement.querySelectorAll(/* CSS selector */);
// 選取元素 (return HTMLCollection)
docement.getElementById(/* HTML id name */);
document.getElementsByClassName(/* HTML classes */);
document.getElementsByTagname(/* HTML tags */);
// 選取 children、descendents
elem.childNodes // 可取得子、子孫、子子孫等元素
elem.children // 只能取得子元素
// 選取 parent
elem.parentNode
elem.parentElement
elem.closest(/* CSS selector */)
elem.closest('elem') // self-selection
// 選取 siblings
elem.previousSibling
elem.previousElementSibling
elem.nextSibling
elem.nextElementSibling
elem.parentElement.children // DOM traversal
容易搞混的選取方法:
Creation and Insertion
/* Creation */
const elem = document.createElement(/* tag */);
/* Insertion */
elem.insertHTML = '';
elem.insertText = '';
elem.insertAdjacentHTML(position, text); //
elem.prepend(another); // 插入成第一個子元素(child)
elem.append(another); // 插入成最後一個子元素(child)
elem.append(el.cloneNode(true)); // 複製元素並插入(※若沒有複製元素,以上都是直接插入或"移動"原元素,不會讓同個元素重複出現在頁面)
elem.before(another); // 並行插入在elem元素前(sibling)
elem.after(another); // 並行插入在elem元素後(sibling)
Deletion
/* Deletion */
elem.remove();
elem.parentElement.removeChild(elem);
Class
/* Class */
elem.classList.add('class1', 'class2', ...);
elem.classList.remove();
elem.classList.toggle();
elem.classList.contains();
Attribute
/* Attribute */
// Built-in attributes
elem.alt
elem.className // 選取class屬性
// Data attributes (data-subName)
// <div data-subname = "data attr">
elem.dataset.subName
// Non built-it attributes
elem.getAttribute('custom-attr');
elem.setAttribute('custom-attr', value);
imgElem.src; // Absolute path (e.g., https:// localhost: 8080/ img1.jpg)
imgElem.getAttribute('src'); // Relative path (real attr value, e.g., /img1.jpg)
Attribute要注意的是「直接用屬性名稱」和用「getAttribute()
方法的差異,如上最後範例:
- 直接用屬性名稱
imgElem.src
、aElem.href
會拿到絕對路徑; - 若是用
getAttribute()
方法取得imgElem.getAttribute('src')
或aElem.getAttribute('href')
會拿到真正的屬性值,如果是設定相對路徑就會拿到相對路徑。
Styles
/* Styles */
// Inline styles (if inline styles exist)
elem.style.color = '#fff';
elem.style.backgroundColor = '#37383d';
// Get current styles (include css styles in .css file)
getComputedStyle(elem).color; // rgb(255, 255, 255)
getComputedStyle(elem).height; // 40px
// Set styles (inlcude css styles in .css file)
elem.style.setProperty(property name, value);
// e.g. 1, change property style document.documentElement.style.setProperty('background-color', 'yellow')
// e.g. 2, change css variable style document.documentElement.style.setProperty('--color-primary', 'yellow')
樣式要注意以下幾點:
.style.xxx
是HTML的標籤元素真的有inline style才會有作用,否則回傳空字串。getComputedStyle()
可以真正取得套用CSS樣式(包含用.css
套用樣式)的元素樣式,並回傳 包含單位的CSS樣式字串 。- 可以用
Number.parseInt
、Number.parseFloat
等方法取得沒有單位的number型別數值。
- 可以用
- 若要改變
.css
檔案設定的屬性或CSS變數,可以用style.setProperty()
方法。
References
The Complete JavaScript Course 2022: From Zero to Expert!
Introduction to the DOM
Document Object Model (DOM)
Element.closest()
Element.insertAdjacentHTML()
CSSStyleDeclaration.setProperty()