使用数据属性

HTML 在设计时就考虑了可扩展性,用于存储应与特定元素关联但无需具有任何已定义含义的数据。data-* 属性允许我们在标准的、语义化的 HTML 元素上存储额外信息,而无需使用其他技巧,例如非标准属性或 DOM 上的额外属性。

HTML 语法

语法很简单。任何元素上以 data- 开头的属性都是 data 属性。假设您有一些文章,并且想存储一些没有视觉表示的额外信息。只需为此使用 data 属性即可。

html
<main>
  <article
    id="electric-cars"
    data-columns="3"
    data-index-number="12314"
    data-parent="cars">
    <!-- Electric car content -->
  </article>

  <article
    id="solar-cars"
    data-columns="3"
    data-index-number="12315"
    data-parent="cars">
    <!-- Solar car content -->
  </article>

  <article
    id="flying-cars"
    data-columns="4"
    data-index-number="12316"
    data-parent="cars">
    <!-- Flying car content -->
  </article>
</main>

JavaScript 访问

JavaScript 中读取这些属性的值也很简单。您可以使用带有完整 HTML 名称的 getAttribute() 来读取它们,但标准定义了一种更简单的方法:一个可以通过 dataset 属性读取的 DOMStringMap

要通过 dataset 对象获取 data 属性,请按属性名称中 data- 后面的部分获取属性(请注意,破折号会被转换为 驼峰式命名)。

js
const article = document.querySelector("#electric-cars");
// The following would also work:
// const article = document.getElementById("electric-cars")

article.dataset.columns; // "3"
article.dataset.indexNumber; // "12314"
article.dataset.parent; // "cars"

每个属性都是一个字符串,可以读取和写入。在上面的例子中,设置 article.dataset.columns = 5 会将该属性更改为 "5"

您还可以使用 document.querySelector()document.querySelectorAll() 配合 data 属性选择器来查找一个或所有匹配的元素。

js
// Find all elements with a data-columns attribute
const articles = document.querySelectorAll("[data-columns]");

// Find all elements with data-columns="3"
const threeColumnArticles = document.querySelectorAll('[data-columns="3"]');
// You can then iterate over the results
threeColumnArticles.forEach((article) => {
  console.log(article.dataset.indexNumber);
});

CSS 访问

请注意,由于 data 属性是纯 HTML 属性,您甚至可以从 CSS 中访问它们。例如,要在文章上显示父级数据,您可以使用 CSS 中的 生成的内容attr() 函数。

css
article::before {
  content: attr(data-parent);
}

您还可以使用 CSS 中的 属性选择器 根据数据更改样式。

css
article[data-columns="3"] {
  width: 400px;
}
article[data-columns="4"] {
  width: 600px;
}

数据值是字符串。数字值在选择器中必须用引号括起来,样式才会生效。

示例

样式变体

假设您有一个 callout 类。现在您想实现不同的变体,例如“note”和“warning”。传统上,人们会使用不同的类名。

html
<div class="callout callout--note">...</div>
<div class="callout callout--warning">...</div>
css
.callout {
  margin: 0.5em 0;
  padding: 0.5em;
  border-radius: 4px;
  border-width: 2px;
  border-style: solid;
}

.callout--note {
  border-color: rgb(15 15 235);
  background-color: rgb(15 15 235 / 0.2);
}
.callout--warning {
  border-color: rgb(235 15 15);
  background-color: rgb(235 15 15 / 0.2);
}

使用 data 属性,您可以考虑以下替代方案:

html
<div class="callout">...</div>
<div class="callout" data-variant="note">...</div>
<div class="callout" data-variant="warning">...</div>
css
.callout {
  margin: 0.5em 0;
  padding: 0.5em;
  border-radius: 4px;
  border-width: 2px;
  border-style: solid;
}

/* Default style */
.callout:not([data-variant]) {
  border-color: rgb(15 15 15);
  background-color: rgb(15 15 15 / 0.2);
}
.callout[data-variant="note"] {
  border-color: rgb(15 15 235);
  background-color: rgb(15 15 235 / 0.2);
}
.callout[data-variant="warning"] {
  border-color: rgb(235 15 15);
  background-color: rgb(235 15 15 / 0.2);
}

这有多种好处:

  • 它消除了许多无效状态,例如应用 callout--note 而不添加 callout,或同时应用多个变体。
  • 单独的 data-variant 属性允许通过 linting 或类型检查对有效值进行静态分析。
  • 切换变体更直观:您可以使用 div.dataset.variant = "warning"; 来代替操作 classList,这需要多个步骤。

将任意数据与 DOM 元素关联

许多 Web 应用程序以 JavaScript 数据作为其 UI 状态的真相来源。在这些情况下,您只需添加渲染所需的 HTML 属性。当所有内容都存在于标记中,而 JavaScript 只用于处理事件、同步状态等情况时,data 属性非常有用。

例如,在我们 带滚动边距的轮播图 示例中,我们有一个已经填充了许多 <img> 元素的 HTML 页面。图片的源最初存储在 data-src 中,以防止任何请求被触发,而真实的 src 仅在 <img> 进入视图时添加。数据(图片源)与元素同处一地,JavaScript 只负责定义行为。

问题

请勿将应可见和可访问的内容存储在 data 属性中,因为辅助技术可能无法访问它们。此外,搜索引擎爬虫可能不会索引 data 属性的值。通常,如果您只打算显示 data 属性,可以直接修改 textContent

另见