[Note] JS: DOM & DOM manipulation


Posted by urlun0404 on 2022-10-22

摘要MDN對DOM的定義:

  1. The data representation of the objects that comprise the structure and content of a document on the web;

  2. A programming interface for web documents;

  3. 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 型別回傳,這兩者的差異在於:

  • HTMLCollectionlife 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.srcaElem.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.parseIntNumber.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()


#frontend #javascript #vanilla javascript







Related Posts

Avoid blocking by navigation menu on mobile device

Avoid blocking by navigation menu on mobile device

MVC 架構 - 以 express 為例

MVC 架構 - 以 express 為例

Conda 常用指令整理

Conda 常用指令整理


Comments