Skip to content

使用数据属性代替HTML类来表示状态

HTML类的问题

通常情况下,当在HTML中表示UI状态时,我们使用类。这通常会转化为React组件或JavaScript代码,根据一些条件来添加或删除类。让我们来看一个例子:

<div id="order">
  <!-- 订单摘要内容 -->
</div>
const orderData = {
  loading: false,
  completed: false,
  errorMessage: null
};

const order = document.querySelector('#order');

order.className = `order-summary
  ${orderData.completed ? 'completed' : ''}
  ${orderData.loading ? 'loading' : ''}
  ${orderData.errorMessage ? 'error' : ''}`;

在这个例子中,我们正在为订单摘要的元素建模。该元素可以处于三种状态之一:加载中已完成_或_错误。我们使用类来表示这些状态,并使用JavaScript根据订单的状态添加或删除这些类。

从UI中确定订单的状态也应该很简单。我们只需检查元素上存在的类即可:

const order = document.querySelector('#order');

const isCompleted = order.getAttribute('data-state') === 'completed';
const isLoading = order.getAttribute('data-state') === 'loading';
const hasError = order.getAttribute('data-state') === 'error';

这种方式可能有点繁琐,但在JavaScript中处理DOM元素通常都是如此。让我们来看一下可以用来样式化这三种状态的一些CSS:

.order-summary.completed {
  background-color: green;
}

.order-summary.loading {
  background-color: yellow;
}

.order-summary.error {
  background-color: red;
}

非常简单易懂。然而,如果由于某种原因,我们从服务器端得到了一些错误的数据怎么办呢?如果订单既是正在加载又是已完成的呢?或者它已经完成但同时又包含错误?那么UI会是什么样子呢?CSS会使用其级联的特性来确定应用哪些样式,这可能会造成混乱。

因此,总结一下,当使用类来表示UI状态时,我们面临以下问题:

  • 使用JavaScript手动将状态映射到类名。
  • 检查元素上的类名是否存在以确定其状态。
  • 当存在多个状态时,可能会出现样式冲突。

使用数据属性的更好方法

如果我告诉你有一种更好的方法?而且这种方法一直存在,已经有很多年了。我指的是数据属性。让我们看看如何使用它们来表示订单摘要的状态:

<div
  id="order"
  class="order-summary"
  data-state="completed"
  data-loading="false"
>
  <!-- 订单摘要内容 -->
</div>

乍一看,我们只是将状态从JavaScript对象移动到DOM中。但这会有很大的不同。首先,我们不再需要将状态从JavaScript映射到DOM。我们只需在元素上设置数据属性即可:

// 假设我们想将订单的状态更改为加载中
const order = document.querySelector('#order');

order.dataset.state = 'loading';
order.dataset.loading = 'true';

我们还可以通过检查数据属性的值来检查订单的状态

const order = document.querySelector('#order');

const isCompleted = order.dataset.state === 'completed';
const isLoading = order.dataset.loading === 'true';
const hasError = order.dataset.error === 'true';

JavaScript的值可以轻松从DOM中检索,没有隐藏的状态,并且很容易进行更改。但是CSS样式如何处理呢?好吧,我们只需要进行一些小的更改:

.order-summary[data-state="completed"] {
  background-color: green;
}
.order-summary[data-state="loading"] {
  background-color: yellow;
}
.order-summary[data-state="error"] {
  background-color: red;
}

我们现在使用的是数据属性选择器,而不是类选择器。这使我们可以根据数据属性的值来定位元素。这比使用类更加灵活,因为我们现在可以在同一个元素上拥有多个状态,而不必担心冲突的样式。

但更有趣的是,我们无法遇到在同一个元素上有两个状态的问题。这是因为数据属性选择器需要完全匹配,否则它将不起作用。因此,如果我们有一个带有类似data-state="loading completed"的元素,它将不匹配任何CSS选择器,也不会被样式化。从DOM中很容易发现它,并且可以确定出问题所在。

结论

正如你所看到的,使用HTML中的数据属性来表示状态比使用类更加灵活可扩展。它强制我们更加明确可调试。我认为这是使用类的一个很好的替代方案,希望你在下一个项目中考虑使用它。