使用JavaScript 建立內容

moduzhang發表於2018-09-03

我們可以編寫相應的 DOM 程式碼,如將返回的元素結果儲存到變數中:

const nanodegreeCard = document.querySelector('.card');

更新現有頁面內容

元素的內部 HTML

每個元素都從元素介面繼承屬性和方法。這意味著,每個元素都有一個 .innerHTML 屬性。這個屬性顧名思義,表示元素內容的標記。我們可以使用這個屬性來:

  • 獲取元素(及其所有子代!)的 HTML 內容
  • 設定元素的 HTML 內容

該屬性返回的是一個字串,也叫 DOMString

注意,.innerHTML 屬性可以設定或返回所選元素內部(即標籤之間)的 HTML 內容。還有一個很少使用的 .outerHTML 屬性。.outerHTML 表示 HTML 元素本身,以及它的子元素

<h1 id="pick-me">大家<span></span></h1>

const innerResults = document.querySelector('#pick-me').innerHTML;
console.log(innerResults); // 會列印字串:"大家<span></span>!"

const outerResults = document.querySelector('#pick-me').outerHTML;
console.log(outerResults); // 會列印字串:"<h1 id="pick-me">大家<span></span></h1>"

元素的文字內容

.textContent 屬性可以:

  • 設定元素及其所有子代的文字內容
  • 返回元素及其所有子代的文字內容

請檢視 MDN 上的 .textContent 文件頁面:textContent 文件

設定元素的文字內容很簡單,就像設定任何其他屬性一樣:

nanodegreeCard.textContent = "I will be the updated text for the nanodegreeCard element!";

注意,將任何看起來像是 HTML 的文字傳遞給 .textContent 屬性,結果仍將顯示為文字。當元素被渲染時,它不會被顯示為 HTML

const myElement = document.querySelector('#test');
myElement.textContent = 'The <strong>Greatest</strong> Ice Cream Flavors';
// 執行這段程式碼後,.textContent 值
// The <strong>Greatest</strong> Ice Cream Flavors

如果你想更新一個元素,包括它的 HTML,則需要使用 .innerHTML 屬性:

myElement.textContent = 'The <strong>Greatest</strong> Ice Cream Flavors'; // 與預期不符

myElement.innerHTML = 'The <strong>Greatest</strong> Ice Cream Flavors';  // 與預期相符

這裡寫圖片描述

在 DOM 中選中該元素,使用 $0 將此元素儲存到變數中。然別使用元素的 .textContent.innerHTML 方法觀察變化。

.innerText 屬性與 .textContent 屬性一樣,.innerText 屬性可以用於獲取/設定元素的文字內容,但這兩個屬性之間有一些重要的區別。

.innerText 會獲取元素的可見文字。這是一個重要的區別!如果使用了 CSS 來隱藏該元素內的任何文字,.innerText 將不會返回該文字,而 .textContent 則會返回該文字。而且,.innerText 不僅遵循 CSS 的隱藏/顯示性質,.innerText 還會遵循像大小寫這樣的更改。

.textContent 屬性成為標準已有一段時間。相反,.innerText 屬性則是 HTML 規範中相對較新的一個。雖然它出現已經有一段時間了,但並沒有獲得所有瀏覽器的完全支援,因為它不是 HTML 規範的一部分。

MDN 上的 innerHTML
MDN 上的 textContent

新增新的頁面內容

.createElement() 方法是 document 物件上的一個​​方法:

// 建立並返回一個 <span> 元素
document.createElement('span');

// 建立並返回一個 <h3> 元素
document.createElement('h3');

這是 MDN 上的 .createElement() 文件頁面:createElement 文件

使用 document.createElement() 來建立元素,其實並不會在頁面上的任何位置新增新建立的元素,並不會將其新增到 DOM,因此它不會出現在頁面上(如果你還記得,DOM 就是頁面的解析表示)。如何將建立的元素內容新增到對應的位置上?

我們可以使用 .appendChild() 方法向頁面新增元素!要使用 .appendChild()方法,需要在另一個元素上呼叫它,而不是 document 物件!

// 建立一個全新的 <span> 元素
const newSpan = document.createElement('span');

// 選擇頁面中的第一個(主)標題
const mainHeading = document.querySelector('h1');

// 新增 <span> 元素作為主標題的最後一個子元素
mainHeading.appendChild(newSpan);

在一個元素上呼叫 .appendChild() 方法,並將該元素傳遞給它進行附加。所附加的元素會被新增為最後一個子元素。

這是 MDN 上的 .appendChild() 文件頁面:appendChild 文件

示例,建立一個新的 <div> 並且插入到 ID 為“div1”的元素前。

<!DOCTYPE html>
<html>
<head>
  <title>||Working with elements||</title>
</head>
<body>
  <div id="div1">The text above has been created dynamically.</div>
</body>
</html>
document.body.onload = addElement;

function addElement () { 
  // create a new div element 
  // and give it some content 
  var newDiv = document.createElement("div"); 
  var newContent = document.createTextNode("Hi there and greetings!"); 
  newDiv.appendChild(newContent); //add the text node to the newly created div. 

  // add the newly created element and its content into the DOM 
  var currentDiv = document.getElementById("div1"); 
  document.body.insertBefore(newDiv, currentDiv); 
}

建立文字節點

就像使用 .createElement() 方法建立新元素一樣,你也可以使用 .createTextNode() 方法建立新的文字節點

  • 建立一個段落元素
  • 建立一個文字節點
  • 將文字節點附加到段落
  • 將段落附加到標籤
const myPara = document.createElement('p');
const textOfParagraph = document.createTextNode('I am the text for the paragraph!');

myPara.appendChild(textOfParagraph);
document.body.appendChild(myPara);

不過,既然你已經瞭解了 .textContent 屬性,以下程式碼也會提供完全相同的結果:

const myPara = document.createElement('p');

myPara.textContent = 'I am the text for the paragraph!';
document.body.appendChild(myPara);

因此,與其建立一個新的文字節點,並將其附加到一個元素上,使用 .textContent 屬性來更新元素的文字更加快捷方便。

如需瞭解更多資訊,請檢視文件:createTextNode() 文件

在其他位置插入 HTML

根據定義,.appendChild() 方法會新增一個元素作為父元素的最後一個子元素。靈活選擇新增子元素的位置?

.insertAdjacentHTML() 方法必須使用兩個引數來呼叫:

  • HTML 的位置
  • 要插入的 HTML 文字

這個方法的第一個引數可以讓我們在四個不同的位置之一插入新的 HTML:

  • beforebegin – 插入 HTML 文字作為前一個子元素
  • afterbegin – 插入 HTML 文字作為第一個子元素
  • beforeend – 插入 HTML 文字作為最後一個子元素
  • afterend – 插入 HTML 文字作為後一個子元素

如果相關元素是一個段落標籤,上述的四個位置將處於下面的視覺化部分:

<!-- beforebegin-出現在段落標籤元素之前-->
<p>
    <!-- afterbegin-出現在段落標籤元素之後,並作為第一個子元素 -->
    Existing text/HTML content
    <!-- beforeend-出現在段落標籤元素結束標記之前,並作為最後一個子項-->
</p>
<!-- afterend-將作為兄弟姐妹項出現在段落標籤元素之後 -->
const mainHeading = document.querySelector('#main-heading');
const htmlTextToAdd = '<h2>Skydiving is fun!</h2>';

mainHeading.insertAdjacentHTML('afterend', htmlTextToAdd);

需要注意的一些要點包括:

  • 如果 DOM 中已經存在一個元素,並將該元素傳遞給 .appendChild(),則 .appendChild() 方法會移動它,而不是複製它
  • 元素的 .textContent 屬性比使用 .createTextNode() 方法建立文字節點更經常被用到
  • .insertAdjacentHTML() 方法的第二個引數必須是文字,而不能傳遞一個元素

請檢視文件頁面,以瞭解更多資訊:insertAdjacentHTML 文件

移除頁面內容

移除子元素

我們可以使用 .removeChild() 方法來…猜對了…移除子元素。基本上,它與 .appendChild() 方法完全相反。因此,就像 .appendChild() 方法一樣,.removeChild() 方法也需要:

  • 一個父元素
  • 將要移除的子元素
<parent-element>.removeChild(<child-to-remove>);

這是 MDN 上的 .removeChild() 文件頁面:removeChild 文件

這裡寫圖片描述

.firstChild.firstElementChild 的不同之處在於,.firstElementChild 總是返回第一個元素,而 .firstChild 則可能返回空白(如果有的話)以保留底層 HTML 原始碼的格式。

使用 .removeChild() 方法的缺點(和解決辦法!)

就像 .appendChild() 方法一樣,.removeChild() 方法也有一個(小小的)缺點。這兩種方法都:

  • 需要訪問父元素才能操作

不過,我們其實並不需要有父元素,因為有一個解決辦法!正如我們可以在父元素上呼叫 .firstElementChild 屬性來訪問它的第一個元素,每個元素也有一個 .parentElement 屬性來引用其父元素!因此,如果我們能夠訪問將要新增或移除的子元素,就可以使用 .parentElement 屬性將“焦點”移動到該元素的父元素。 然後,我們就可以在被引用的父元素上呼叫 .removeChild()(或 .appendChild())了。

const mainHeading = document.querySelector('h1');
mainHeading.parentElement.removeChild(mainHeading);

這行程式碼以 mainHeading 變數開頭。它呼叫了 .parentElement,因此下一個程式碼的焦點在父元素上。然後,在父元素上呼叫 .removeChild()。最後,mainHeading 本身作為需要從其父元素中移除的元素被傳遞。

我們可以使用 .remove() 方法來直接移動子元素:

const mainHeading = document.querySelector('h1');
mainHeading.remove();

這是 MDN 上的 .remove() 文件頁面:.remove() 文件

設定頁面內容樣式

在本部分,我們將學習如何使用以下屬性和方法來控制頁面和元素樣式

  • .style.<prop>
  • .cssText()
  • .setAttribute()
  • .className
  • .classList

CSS 特異性

特異性水平 CSS規則
特異性最低 樣式表中的規則
特異性較高 標籤 <style> 中的規則
特異性最高 標籤樣式屬性中的規則

根據 MDN,“特異性”是指:瀏覽器用於確定哪個 CSS 屬性值與元素最相關,因此將被應用的方式。

基本上,樣式規則越接近元素,它的特異性就越高。例如,某個元素的樣式屬性中的規則將覆蓋 CSS 樣式表中該元素的樣式規則。此外還有所使用的選擇器型別的特異性,ID的特異性高於類MDN 上的特異性

修改元素的樣式屬性

我們可以使用 .style 屬性來訪問元素的樣式屬性!

const mainHeading = document.querySelector('h1');
mainHeading.style.color = 'red';

在使用 .style 屬性時,每次只能修改一個 CSS 樣式。這就是為什麼先前的程式碼中有 .style.color = 'red',而不只是 .style = 'red'

請檢視文件頁面,以瞭解更多資訊:樣式文件

我們可以使用 .style.cssText 屬性一次設定多個 CSS 樣式

const mainHeading = document.querySelector('h1');
mainHeading.style.cssText = 'color: blue; background-color: orange; font-size: 3.5em';

請注意,在使用 .style.cssText 屬性時,你要像在樣式表中一樣編寫 CSS 樣式;因此,要寫 font-size,而不是 fontSize。這與使用單獨的 .style.<property> 方式有所不同。還有 .style.cssText 將覆蓋 .style 屬性中已有的任何內容

設定元素的屬性

還有一種設定元素樣式的方法是完全繞過 .style.<property>.style.cssText 屬性,而使用 .setAttribute() 方法:

const mainHeading = document.querySelector('h1');
mainHeading.setAttribute('style', 'color: blue; background-color: orange; font-size: 3.5em;');

請檢視文件頁面,以瞭解更多資訊:樣式文件

.setAttribute() 方法不僅可以設定頁面元素的樣式。你還可以使用該方法來設定元素的任何屬性

const mainHeading = document.querySelector('h1');

// 新增一個 ID 到標題的兄弟元素
mainHeading.nextElementSibling.setAttribute('id', 'heading-sibling');

// 使用新新增的 ID 來訪問該元素
document.querySelector('#heading-sibling').style.backgroundColor = 'red';

最後兩行可以合併成一行,以繞過設定 ID,而直接設定元素樣式:

mainHeading.nextElementSibling.style.backgroundColor = 'red';

訪問元素的類

.className 屬性,該屬性會返回元素所有類的字串。我們可以使用 .className 來訪問類列表:

<h1 id="main-heading" class="ank-student jpk-modal">Learn Web Development at Udacity</h1>
const mainHeading = document.querySelector('#main-heading');

// 將類的列表儲存在一個變數中
const listOfClasses = mainHeading.className;

// 列印出字串 "ank-student jpk-modal"
console.log(listOfClasses);

.className 屬性會返回一個有空格的類字串。不過,我們可以使用 JavaScript 字串方法 .split() 將這個有空格的字串轉換為一個陣列:

const arrayOfClasses = listOfClasses.split(' ');

// 列印出字串陣列 ["ank-student", "jpk-modal"]
console.log(arrayOfClasses);

現在,藉助這個類陣列,我們可以進行任何大規模的資料計算:

  • 使用 for 迴圈遍歷類名列表
  • 使用 .push() 向列表中新增專案
  • 使用 .pop() 從列表中移除專案

.className 是一個屬性,因此我們可以通過給該屬性賦一個字串來設定它的值

mainHeading.className = "im-the-new-class";

以上程式碼會抹掉元素的 class 屬性中原有的任何類,並將其替換為單個類im-the-new-class

由於 .className 會返回一個字串,因此很難新增或移除單個類。讓我們來使用新的 .classList 屬性吧。.classList 是替代 element.className 作為空格分隔的字串訪問元素的類列表的一種方便的方法。返回一個元素的類屬性的實時 DOMTokenList 集合。檢視 classList 文件

const mainHeading = document.querySelector('#main-heading');

// 將類的列表儲存在一個變數中
const listOfClasses = mainHeading.classList;

// 列印出 ["ank-student", "jpk-modal"]
console.log(listOfClasses);

.classList 屬性擁有自己的一些屬性,其中一些最常用的是:

  • .add() - 向列表中新增類
  • .remove() - 從列表中移除類
  • .toggle() - 如果某個類尚不存在,則向列表中新增它;如果某個類已經存在,則從列表中移除它
  • .contains() - 根據該類是否存在於列表中返回一個布林值

更多地使用 .classList 屬性,它是目前為止這些技能中最有用的屬性,而且它可以幫助你將 CSS 樣式與 JavaScript 程式碼保持分開。

相關文章