data-* HTML 自定義屬性及 dataset

JS30 Day1 第一次看到 data-* 屬性,學習 DOM 之後發現真是太好用了阿!

筆記內容為學習過程中的紀錄,內容可能未臻完善,如有錯漏,歡迎留言,謝謝!

data-* 基本介紹

[MDN 說明]

HTML 標籤除了預設的屬性之外,其實還有個很好用的自定義屬性 data-* ,這個東西在開始進行 DOM 操作後,更可以明顯感受到它的方便性。通常我們在眾多 HTML 標籤中要針對特定幾個元素做操作時,會使用 id 或 class 來指定,但實際使用下來不夠彈性。例如:

現在有 52 張撲克牌,我和朋友玩了撿紅點。計分時黑牌不計分、紅牌數值相加。我可以直接用 class name “card” 來套用同樣的卡背樣式。但如果我想把所有吃到”紅色牌分數”相加時,現有的屬性沒辦法滿足我的需求。

1
2
3
4
5
6
7
8
<!-- 用 <div> 做出 52 張牌 -->
<div class="card">A</div>
<div class="card">2</div>
<div class="card">3</div>
...(略)
<div class="card">J</div>
<div class="card">Q</div>
<div class="card">K</div>

於是,我就可以用 data-* 來加上我需要的屬性內容。 用 data-suit 來表示花色、 data-value 來表示數字。這樣,我就可以一眼看出這張牌的顏色和數字了!

1
2
3
4
5
6
7
8
<!-- 加上花色及數值屬性 -->
<div class="card" data-suit="club" data-value="1">A</div>
<div class="card" data-suit="diamond" data-value="2">2</div>
<div class="card" data-suit="heart" data-value="3">3</div>
...(略)
<div class="card" data-suit="heart" data-value="11">J</div>
<div class="card" data-suit="spade" data-value="12">Q</div>
<div class="card" data-suit="spade" data-value="13">K</div>

使用 data-* 可以新增一個”自定義屬性”,並給這個屬性一個”值”,有了這個設定之後,就可以更有針對性及彈性的對特定元素進行操作。

命名規則

(很重要! 和後面提到的 dataset 應用有關!)

  • 同 class 命名慣例,用 - 串接字詞。
  • 名字絕對不能以 xml 起頭。
  • 名字只能包含小寫字母、數字、dash(-)、點(.)、冒號(:)和下底線(_)。

補充說明

data-* 所儲存的屬性值型別都是字串,如果要進行四則運算要記得先轉換型別!

CSS 應用

CSS 選擇器

我們常以 class 及 id 來定義 CSS 樣式。其實 CSS 選擇器中有一個屬性選擇器,可以依屬性值來選擇特定元素。接續上面的撲克牌為例,把花色為愛心/方塊的牌顯示為紅色:

1
2
3
4
5
/* 選擇屬性為特定值的元素 */
[data-suit="heart"],
[data-suit="diamond"] {
color: red;
}

CSS content 及 attr()

content 可以用 CSS 直接生成靜態文字; attr() 則是可以讀取”屬性值”。
如果有3個設好 data-value 的撲克牌,我要讓它在 <div></div> 中間加入屬性的值:

1
2
3
4
<!-- 原本未加 CSS 狀態 -->
<div class="card" data-value="A"></div>
<div class="card" data-value="2"></div>
<div class="card" data-value="3"></div>

設置 CSS content:

1
2
3
div::after {
content: attr(data-value)
}

CSS 渲染過後的 HTML 會呈現:

1
2
3
<div class="card" data-value="A">A</div>
<div class="card" data-value="2">2</div>
<div class="card" data-value="3">3</div>

DOM 與 JavaScript 應用

DOM querySelector

  • 在使用 querySelector 時,可以直接指定屬性值。以”選擇所有梅花牌”為例:

    1
    2
    3
    4
    // 選取所有含 data-suit="club" 的節點
    document.querySelectors('[data-suit="club"]')
    // 選取所有含 data-suit="club" 的 <div> 節點
    document.querySelectors('div[data-suit="club"]')
  • 也可以更彈性的運用,使用 template 代入屬性值。以 [JS30 Day1 JavaScript Drum Kit] 為例:
    在 HTML 部分設置了4個按鍵元素(A、S、D、F),並為每個按鍵標上編號。

    1
    2
    3
    4
    <div data-key="65" class="key">A</div>
    <div data-key="83" class="key">S</div>
    <div data-key="68" class="key">D</div>
    <div data-key="70" class="key">F</div>

    設置監聽事件,自動讀取事件紀錄的 keyCode 並將數值代入 template 中。

    1
    2
    3
    4
    5
    6
    7
    8
    window.addEventListener('keydown', playAudio)
    function playAudio(event) {
    const key = document.querySelector(`.key[data-key="${event.keyCode}"]`)
    // 其他程式碼(略)
    }

    // 例如: 按下"A"鍵,事件紀錄的 keyCode:65 ,這裡就會直接把65代入。上面的程式碼會變成:
    const key = document.querySelector('.key[data-key="65"]')

HTMLElement.dataset

[MDN 說明]

命名轉換

dash-style to camelCase

  1. 刪去前綴字 data-
  2. 每個 - 後的第一個字母轉為大寫,刪去中間 - 後連接字串。
    例如: data-abc-def-ghi 會被轉換為 abcDefGhi

實際運用

範例取自 MDN 文件
有個 HTML 元素如下:

1
2
3
<div id="user" data-id="1234567890" data-user="johndoe">
John Doe
</div>

如果我要取它的 data-* 屬性值,取值方式如下:

1
2
3
4
5
// 選取要取值的對象
const user = document.querySelector('#user')
// 開始取值
console.log(user.dataset.id) // 回傳 '1234567890'
console.log(user.dataset.user) // 回傳 'johndoe'

文章內容如有錯誤,歡迎留言討論!


本 Blog 上的所有文章除特别聲明外,均採用 CC BY-SA 4.0 協議 ,轉載請註明出處!