博客 / 詳情

返回

HTML5 自定義屬性 data-*:別再把數據塞進 class 裏了!

🧑‍💻 寫在開頭

點贊 + 收藏 === 學會🤣🤣🤣

前言:由於“無處安放”而引發的混亂

在 HTML5 普及之前,前端開發者為了在 DOM 元素上綁定一些數據(比如用户 ID、商品價格、狀態碼),可謂是八仙過海,各顯神通:

  1. 隱藏域流派:到處塞 <input type="hidden" value="123">,導致 HTML 結構像個堆滿雜物的倉庫。
  2. Class 拼接流派<div class="btn item-id-8848">,然後用正則去解析 class 字符串提取 ID。這簡直是在用 CSS 類名當數據庫用,類名聽了都想離家出走。
  3. 自定義非標屬性流派:直接寫 <div my_id="123">。雖然瀏覽器大多能容忍,但這就好比在公共泳池裏裸泳——雖然沒人抓你,但不合規矩且看着尷尬。

直到 HTML5 引入了 data-*  自定義數據屬性,這一切終於有了“官方標準”。


第一階段:基礎——它長什麼樣?

data-* 屬性允許我們在標準 HTML 元素中存儲額外的頁面私有信息。

1. HTML 寫法

語法非常簡單:必須以 data- 開頭,後面接上你自定義的名稱。

<!-- ❌ 錯誤示範:不要大寫,不要亂用特殊符號 -->
<div data-User-Id="1001"></div> 

<!-- ✅ 正確示範:全小寫,連字符連接 -->
<div 
  id="user-card"
  data-id="1001" 
  data-user-name="juejin_expert" 
  data-value="99.9"
  data-is-vip="true"
>
  用户信息卡片
</div>

2. CSS 中的妙用

很多人以為 data-* 只是給 JS 用的,其實 CSS 也能完美利用它。

場景一:通過屬性選擇器控制樣式

/* 當 data-is-vip 為 "true" 時,背景變金 */
div[data-is-vip="true"] {
  background: gold;
  border: 2px solid orange;
}

場景二:利用 attr() 顯示數據
這是一個非常酷的技巧,可以用來做 Tooltip 或者計數器顯示。

div::after {
  /* 直接把 data-value 的值顯示在頁面上 */
  content: "當前分值: " attr(data-value);
  font-size: 12px;
  color: #666;
}

第二階段:進階——JavaScript 如何讀寫?

這才是重頭戲。在 JS 中操作 data-* 有兩種方式:傳統派 和 現代派

1. 傳統派:getAttribute / setAttribute

這是最穩妥的方法,兼容性最好(雖然現在也沒人要兼容 IE6 了)。

const el = document.getElementById('user-card');

// 讀取
const userId = el.getAttribute('data-id'); // "1001"

// 修改
el.setAttribute('data-value', '100');

特點:讀出來永遠是字符串。哪怕你存的是 100,取出來也是 "100"。

2. 現代派:dataset API (推薦 ✨)

HTML5 為每個元素提供了一個 dataset 對象(DOMStringMap),它將所有的 data-* 屬性映射成了對象的屬性。

這裏有個大坑(或者説是規範),請務必注意:
HTML 中的 連字符命名 (kebab-case)  會自動轉換為 JS 中的 小駝峯命名 (camelCase)

const el = document.getElementById('user-card');

// 1. 訪問 data-id
console.log(el.dataset.id); // "1001"

// 2. 訪問 data-user-name (注意變身了!)
console.log(el.dataset.userName); // "juejin_expert"
// ❌ el.dataset.user-name 是語法錯誤
// ❌ el.dataset['user-name'] 是 undefined

// 3. 修改數據
el.dataset.value = "200"; 
// HTML 會自動變成 data-value="200"

// 4. 刪除數據
delete el.dataset.isVip;
// HTML 中的 data-is-vip 屬性會被移除

💡 敲黑板:dataset 裏的屬性名不支持大寫字母。如果你在 HTML 裏寫 data-MyValue="1", 瀏覽器會強制轉為小寫 data-myvalue,JS 裏就得用 dataset.myvalue 訪問。所以,HTML 里老老實實全小寫吧。


第三階段:深入——類型陷阱與性能權衡

1. 一切皆字符串

不管你賦給 dataset 什麼類型的值,最終都會被轉為字符串。

el.dataset.count = 100;        // HTML: data-count="100"
el.dataset.active = true;      // HTML: data-active="true"
el.dataset.config = {a: 1};    // HTML: data-config="[object Object]" -> 災難!

避坑指南

  • 如果你要存數字,取出來時記得 Number(el.dataset.count)。
  • 如果你要存布爾值,判斷時不能簡單用 if (el.dataset.active),因為 "false" 字符串也是真值!要用 el.dataset.active === 'true'。
  • 千萬不要試圖在 data-* 裏存複雜的 JSON 對象。如果非要存,請使用 JSON.stringify(),但在 DOM 上掛載大量字符串數據會影響性能。

2. 性能考量

  • 讀寫速度:dataset 的訪問速度在現代瀏覽器中非常快,但在極高頻操作下(比如每秒幾千次),直接操作 JS 變量肯定比操作 DOM 快。
  • 重排與重繪:修改 data-* 屬性會觸發 DOM 變更。如果你的 CSS 依賴屬性選擇器(如 div[data-status="active"]),修改屬性可能會觸發頁面的重排(Reflow)或重繪(Repaint)。

第四階段:實戰——優雅的事件委託

data-value 最經典的用法之一就是在列表項的事件委託中。

需求:點擊列表中的“刪除”按鈕,刪除對應項。

<ul id="todo-list">
  <li>
    <span>學習 HTML5</span>
    <!-- 把 ID 藏在這裏 -->
    <button class="btn-delete" data-id="101" data-action="delete">刪除</button>
  </li>
  <li>
    <span>寫掘金文章</span>
    <button class="btn-delete" data-id="102" data-action="delete">刪除</button>
  </li>
</ul>

  

const list = document.getElementById('todo-list');

list.addEventListener('click', (e) => {
  // 利用 dataset 判斷點擊的是不是刪除按鈕
  const { action, id } = e.target.dataset;

  if (action === 'delete') {
    console.log(`準備刪除 ID 為 ${id} 的條目`);
    // 這裏發送請求或操作 DOM
    // deleteItem(id);
  }
});

為什麼這麼做優雅?
你不需要給每個按鈕都綁定事件,也不需要去分析 DOM 結構(比如 e.target.parentNode...)來找數據。數據就在元素身上,唾手可得。


總結與“禁忌”

HTML5 的 data-* 屬性是連接 DOM 和數據的一座輕量級橋樑。

什麼時候用?

  • 當需要把少量數據綁定到特定 UI 元素上時。
  • 當 CSS 需要根據數據狀態改變樣式時。
  • 做事件委託需要傳遞參數時。

什麼時候別用?(禁忌)

  1. 不要存儲敏感數據:用户可以直接在瀏覽器控制枱修改 DOM,千萬別把 data-password 或 data-user-token 放在這。
  2. 不要當數據庫用:別把幾 KB 的 JSON 數據塞進去,那是 JS 變量或者是 IndexDB 該乾的事。
  3. SEO 無用:搜索引擎爬蟲通常不關心 data-* 裏的內容,重要的文本內容還是要寫在標籤裏。

最後一句
代碼整潔之道,始於不再亂用 Class。下次再想存個 ID,記得想起那個以 data- 開頭的帥氣屬性。

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.