下面给你一份 *完整详解 + 多场景完整代码示例的《HTML5 data- 自定义数据属性教程》**。包含基础语法、读取/写入方式、JS 交互、事件传参、动态修改、数据绑定和实际项目案例。

内容清晰、可直接用于学习、教学或文档撰写。


HTML5 data- 自定义数据属性详解*

data-* 属性是 HTML5 用于存储自定义数据的标准方式,常用于:

  • 存储与 DOM 元素相关的参数
  • 在 JS 中读取 / 修改配置
  • 在组件或插件中传递数据
  • 与后端返回的数据绑定
  • 事件委托中识别点击对象

格式如下:

<div data-xxx="value"></div>

其中:

  • xxx 为自定义名称(必须小写,不能包含大写字母)
  • value 为任意字符串(数字、对象均可 JSON 化)

一、基础用法示例(最常见)

<button id="btn" data-id="101" data-type="delete">
    删除商品
</button>

<script>
const btn = document.getElementById("btn");
console.log(btn.dataset.id);      // "101"
console.log(btn.dataset.type);    // "delete"
</script>


二、通过 JavaScript 操作 data-* 属性

1. 读取 data 属性

element.dataset.name

示例:

<div id="user" data-name="李若萱" data-age="20"></div>

<script>
const user = document.getElementById("user");
console.log(user.dataset.name); // 李若萱
console.log(user.dataset.age);  // 20
</script>


2. 修改 data 属性

element.dataset.age = "22";
element.dataset.role = "VIP";


3. 删除 data 属性

delete element.dataset.age;


三、data-* 命名规则(驼峰转连字符)

HTML 中用连字符:

<div data-user-name="Jack"></div>

JS 中自动转换为驼峰:

element.dataset.userName // Jack


四、场景示例 1:事件委托中识别点击对象(非常常用)

适用于列表、导航栏、商品卡片等。

<ul id="menu">
  <li data-page="home">首页</li>
  <li data-page="products">商品</li>
  <li data-page="contact">联系</li>
</ul>

<script>
document.getElementById("menu").addEventListener("click", function(e) {
    if (e.target.dataset.page) {
        console.log("跳转到:" + e.target.dataset.page);
    }
});
</script>


五、场景示例 2:作为组件参数(轮播图/弹窗常用)

<div class="slider" 
     data-autoplay="true"
     data-delay="3000"
     data-direction="horizontal">
</div>

JS 初始化:

const slider = document.querySelector(".slider");

const config = {
    autoplay: slider.dataset.autoplay === "true",
    delay: Number(slider.dataset.delay),
    direction: slider.dataset.direction
};

console.log(config);


六、场景示例 3:存储 JSON 数据

<div id="product" 
     data-info='{"id":1001,"price":299,"title":"运动鞋"}'>
</div>

<script>
const p = document.getElementById("product");
const info = JSON.parse(p.dataset.info);

console.log(info.id);      // 1001
console.log(info.price);   // 299
console.log(info.title);   // 运动鞋
</script>


七、场景示例 4:结合 CSS 使用 data 属性(高级技巧)

<style>
button[data-state="danger"] {
    background: red;
    color: white;
}
</style>

<button data-state="danger">删除</button>

无需 JS 即可控制样式,非常灵活。


八、场景示例 5:用于动画控制

<div class="box" data-speed="2" data-distance="200"></div>

<script>
const box = document.querySelector(".box");

let speed = Number(box.dataset.speed);
let distance = Number(box.dataset.distance);

console.log(speed, distance);
</script>


九、示例:列表动态点击加载数据

<ul id="list">
    <li data-id="1" data-name="小明">小明</li>
    <li data-id="2" data-name="小红">小红</li>
    <li data-id="3" data-name="小李">小李</li>
</ul>

<div id="info"></div>

<script>
document.getElementById("list").addEventListener("click", e => {
    if (!e.target.dataset.id) return;

    document.getElementById("info").innerText =
        `ID: ${e.target.dataset.id},姓名: ${e.target.dataset.name}`;
});
</script>


十、动态创建带 data-* 属性的 DOM

let li = document.createElement("li");
li.dataset.index = 5;
li.dataset.title = "示例标题";

document.body.appendChild(li);


十一、data-* 属性 vs JS 全局变量 vs DOM 属性并存区别

类型存储位置特点
data-*存储于 DOM,标准方式推荐方式,结构化
JS 全局变量JS 内存不适用于 DOM 数据
DOM 属性element.xxx不建议随意扩展

data- 是 HTML 官方标准扩展 DOM 数据的方式*


十二、综合完整示例:商品卡片点击加入购物车

<div class="item" 
     data-id="3001" 
     data-price="199"
     data-title="蓝牙耳机">
    <h3>蓝牙耳机</h3>
    <button class="add">加入购物车</button>
</div>

<script>
document.querySelector(".item .add").onclick = function(e) {
    const item = e.target.parentElement;
    const id = item.dataset.id;
    const price = Number(item.dataset.price);
    const title = item.dataset.title;

    console.log(`加入购物车:${title} (ID:${id}) ¥${price}`);
};
</script>


✔ 总结(背一下就行)

  • data-* 用于存储自定义数据,是 HTML5 推荐方式
  • JS 使用 element.dataset.xxx 访问
  • HTML 中连字符 → JS 自动转驼峰
  • 配合事件委托、组件配置、样式控制非常强大
  • 可以存 JSON、数字、字符串等

明白,我帮你整理一个完整实战示例,演示如何在 购物车、Tab 切换、懒加载场景中使用 data-* 属性,全部都是可直接运行的 HTML5+JS 示例,方便你学习和项目参考。


1️⃣ 购物车示例(动态加入/删除商品)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>购物车 data-* 示例</title>
<style>
  body{font-family:Arial;margin:20px}
  .item{border:1px solid #ccc;padding:12px;margin-bottom:12px;border-radius:6px;display:flex;justify-content:space-between;align-items:center}
  .cart{margin-top:20px;border:1px solid #eee;padding:12px;border-radius:6px;background:#fafafa}
</style>
</head>
<body>

<h2>商品列表</h2>
<div class="item" data-id="101" data-title="蓝牙耳机" data-price="199">
    <span>蓝牙耳机 ¥199</span>
    <button class="add">加入购物车</button>
</div>
<div class="item" data-id="102" data-title="无线鼠标" data-price="89">
    <span>无线鼠标 ¥89</span>
    <button class="add">加入购物车</button>
</div>
<div class="item" data-id="103" data-title="机械键盘" data-price="499">
    <span>机械键盘 ¥499</span>
    <button class="add">加入购物车</button>
</div>

<div class="cart">
    <h3>购物车</h3>
    <ul id="cartList"></ul>
    <strong id="total">总计: ¥0</strong>
</div>

<script>
const cartList = document.getElementById('cartList');
const totalEl = document.getElementById('total');
let total = 0;

document.querySelectorAll('.item .add').forEach(btn => {
    btn.addEventListener('click', e => {
        const item = e.target.parentElement;
        const id = item.dataset.id;
        const title = item.dataset.title;
        const price = Number(item.dataset.price);

        total += price;
        const li = document.createElement('li');
        li.textContent = `${title} ¥${price} `;
        const removeBtn = document.createElement('button');
        removeBtn.textContent = '删除';
        removeBtn.addEventListener('click', ()=> {
            total -= price;
            li.remove();
            totalEl.textContent = `总计: ¥${total}`;
        });
        li.appendChild(removeBtn);
        cartList.appendChild(li);
        totalEl.textContent = `总计: ¥${total}`;
    });
});
</script>

</body>
</html>


2️⃣ Tab 切换示例(通过 data-tab 识别内容)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tab 切换 data-* 示例</title>
<style>
  .tabs{display:flex;gap:10px;margin-bottom:10px}
  .tabs button{padding:8px 12px;border:1px solid #ccc;background:#f5f5f5;border-radius:4px;cursor:pointer}
  .tabs button.active{background:#1d72ff;color:#fff;border-color:#1d72ff}
  .tab-content{border:1px solid #eee;padding:12px;border-radius:6px}
  .tab-content > div{display:none}
  .tab-content > div.active{display:block}
</style>
</head>
<body>

<div class="tabs">
    <button data-tab="1" class="active">首页</button>
    <button data-tab="2">商品</button>
    <button data-tab="3">关于</button>
</div>

<div class="tab-content">
    <div data-tab="1" class="active">这是首页内容</div>
    <div data-tab="2">这里是商品列表</div>
    <div data-tab="3">关于我们介绍</div>
</div>

<script>
const tabButtons = document.querySelectorAll('.tabs button');
const tabContents = document.querySelectorAll('.tab-content > div');

tabButtons.forEach(btn => {
    btn.addEventListener('click', () => {
        const tabId = btn.dataset.tab;
        tabButtons.forEach(b=>b.classList.remove('active'));
        tabContents.forEach(c=>c.classList.remove('active'));

        btn.classList.add('active');
        document.querySelector(`.tab-content > div[data-tab="${tabId}"]`).classList.add('active');
    });
});
</script>

</body>
</html>


3️⃣ 图片懒加载示例(使用 data-src 属性)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片懒加载 data-* 示例</title>
<style>
  img{display:block;margin-bottom:20px;width:100%;max-width:400px;border-radius:6px}
</style>
</head>
<body>

<h2>图片懒加载示例</h2>
<img data-src="https://picsum.photos/id/1015/600/400" alt="示例1" class="lazy">
<img data-src="https://picsum.photos/id/1016/600/400" alt="示例2" class="lazy">
<img data-src="https://picsum.photos/id/1018/600/400" alt="示例3" class="lazy">

<script>
const lazyImages = document.querySelectorAll('img.lazy');

const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
        if(entry.isIntersecting){
            const img = entry.target;
            img.src = img.dataset.src;
            img.classList.remove('lazy');
            obs.unobserve(img);
        }
    });
}, {rootMargin: "0px 0px 50px 0px"});

lazyImages.forEach(img => observer.observe(img));
</script>

</body>
</html>