以下是使用Day.js实现时间状态显示的

By admin, 26 June, 2025
推理
我们使用day.js库来处理时间。目标是根据当前时间与开始时间(data-date)和结束时间(data-date-end)的比较,显示对应的状态(未开始、进行中、已结束)。
步骤:
1. 获取当前时间。
2. 遍历每个具有.status-btn类的元素。
3. 从元素的data-date和data-date-end属性中获取开始时间和结束时间。
4. 使用day.js将字符串转换为dayjs对象。
5. 比较当前时间与开始时间、结束时间:
- 如果当前时间在开始时间之前:显示“未开始”(state-upcoming),隐藏其他两个。
- 如果当前时间在开始时间之后且在结束时间之前:显示“进行中”(state-ongoing),隐藏其他两个。
- 如果当前时间在结束时间之后:显示“已结束”(state-past),隐藏其他两个。

注意:在HTML中,每个状态都有一个hidden类,我们需要根据条件移除或添加这个类来控制显示。

实现:
我们将为每个.status-btn元素执行以下操作:
let currentDate = dayjs(); // 当前时间
let startDate = dayjs(element.dataset.date); // 开始时间
let endDate = dayjs(element.dataset.dateEnd); // 结束时间

// 比较
if (currentDate.isBefore(startDate)) {
显示未开始,隐藏其他
} else if (currentDate.isAfter(startDate) && currentDate.isBefore(endDate)) {
显示进行中,隐藏其他
} else if (currentDate.isAfter(endDate)) {
显示已结束,隐藏其他
}

但是注意:有可能当前时间正好等于开始时间或结束时间?根据需求,我们可以这样处理:
- 等于开始时间:可以算作“进行中”
- 等于结束时间:算作“已结束”

我们可以使用:
currentDate.isSameOrAfter(startDate) && currentDate.isSameOrBefore(endDate) 表示进行中
但是这样写比较复杂,我们可以用:
if (currentDate.isBefore(startDate)) { ... }
else if (currentDate.isAfter(endDate)) { ... }
else { 进行中 }

因为进行中包括开始时间之后到结束时间之前,也包括开始时间和结束时间当天(如果精确到天的话)。但是这里我们的日期字符串是到天的,所以比较时我们使用天为单位。

但是注意:dayjs默认比较是精确到毫秒的,如果我们只关心日期(不关心时间),那么我们需要使用dayjs的startOf('day')来归一化到同一天的0点。

由于我们的日期字符串是"YYYY-MM-DD",我们可以直接使用dayjs(dateString)来创建,它会解析为当天的0点。

所以比较时,我们直接使用dayjs对象即可,因为当前时间(dayjs())是包含时间的,而我们的日期字符串解析后是那一天的0点。

例如:开始日期是2025-05-24,那么解析后的时间是2025-05-24 00:00:00。

因此:
- 当前时间如果早于2025-05-24 00:00:00,就是未开始。
- 当前时间如果在2025-05-24 00:00:00之后,且在2025-05-25 00:00:00之前(即2025-05-24全天),那么进行中。
- 当前时间在2025-05-25 00:00:00之后,就是已结束。

但是注意:结束时间的那一天,比如2025-05-25,那么这一天的0点开始,我们就认为已经结束了?因为结束时间我们通常认为是在结束日期的0点就结束?这取决于业务逻辑。

根据常见的理解:
- 活动在开始日期0点开始,在结束日期0点结束?还是结束日期的24点结束?
- 通常,我们可能希望活动在结束日期的24点结束,但是我们的结束日期只给到天,没有时间。所以解析后是结束日期的0点。这样,结束日期的0点一到,活动就结束了。

如果业务要求活动在结束日期当天仍然有效,那么我们需要将结束时间设置为结束日期的23:59:59。但是这里给出的属性是日期,没有时间。

因此,我们需要明确:如何定义时间范围?

假设:
- 开始日期:2025-05-24 表示活动从2025-05-24 00:00:00开始
- 结束日期:2025-05-25 表示活动到2025-05-25 23:59:59结束

但是,我们的data-date-end属性只提供了日期,所以解析后是2025-05-25 00:00:00。这样,如果我们用这个结束日期对象去比较,那么2025-05-25 00:00:00之后(比如2025-05-25 01:00:00)就结束了,但实际我们可能希望2025-05-25全天都是活动时间。

因此,我们需要调整结束时间:将结束日期加上一天(即变成2025-05-26 00:00:00),然后判断当前时间是否小于这个时间。这样,2025-05-25全天都属于活动时间。

或者,我们可以将结束时间设置为当天的23:59:59,但是这样需要操作字符串。

另一种方法:在比较时,使用结束日期的下一天的0点作为结束时间点(即活动在结束日期的24点结束)。

所以:
let startDate = dayjs(element.dataset.date);
let endDate = dayjs(element.dataset.dateEnd).add(1, 'day'); // 这样结束时间就是结束日期下一天的0点

然后:
if (currentDate.isBefore(startDate)) -> 未开始
else if (currentDate.isBefore(endDate)) -> 进行中(因为endDate已经是结束日期的下一天0点,所以小于这个时间就是直到结束日期的23:59:59)
else -> 已结束

但是注意:开始日期不需要调整,因为开始日期就是当天的0点。

因此,我们可以这样处理结束时间。

步骤:
1. 引入day.js
2. 等待DOM加载完成
3. 选择所有.status-btn元素
4. 遍历每个元素,获取data-date和data-date-end属性
5. 将开始时间转换为dayjs对象
6. 将结束时间转换为dayjs对象,并加上1天(这样结束时间就是结束日期下一天的0点)
7. 获取当前时间
8. 比较并显示对应的状态

代码实现:

假设已经引入了day.js,并且DOM已经加载。

注意:隐藏其他状态,即移除当前需要显示的状态的hidden类,给其他两个状态添加hidden类。

我们可以这样操作:
const statusElement = element.querySelector('.state-upcoming');
const ongoingElement = element.querySelector('.state-ongoing');
const pastElement = element.querySelector('.state-past');

// 先全部隐藏
statusElement.classList.add('hidden');
ongoingElement.classList.add('hidden');
pastElement.classList.add('hidden');

// 然后根据条件显示其中一个
if (currentDate.isBefore(startDate)) {
statusElement.classList.remove('hidden');
} else if (currentDate.isBefore(endDate)) { // 注意:endDate是结束日期的下一天0点
ongoingElement.classList.remove('hidden');
} else {
pastElement.classList.remove('hidden');
}

但是注意:有可能没有某个状态元素?根据提供的HTML结构,三个状态元素都是存在的,所以可以直接操作。

完整代码示例(假设在DOMContentLoaded事件中):
角色
assistant
content

以下是使用Day.js实现时间状态显示的完整解决方案:

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>活动状态显示</title>
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js"></script&gt;
<style>
.hidden { display: none; }
.status-btn { margin: 20px 0; }
.item-moer { padding: 5px 10px; margin: 5px; border-radius: 4px; }
.state-upcoming { background-color: #ffecd9; color: #ff8c00; }
.state-ongoing { background-color: #e6f7ff; color: #1890ff; }
.state-past { background-color: #f6ffed; color: #52c41a; }
</style>
</head>
<body>
<!-- 示例HTML结构 -->
<div class="status-btn" data-date="2025-05-24" data-date-end="2025-05-25">
<div class="item-moer item-state-start state-upcoming hidden">
<span>未开始</span>
</div>
<div class="item-moer item-state-start state-ongoing hidden">
<a href="/zh-hans/node/1497">进行中</a>
</div>
<div class="item-moer item-state-end state-past hidden">
<span>已结束</span>
</div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
// 获取所有状态容器
const statusContainers = document.querySelectorAll('.status-btn');

statusContainers.forEach(container => {
// 获取时间数据
const startDate = dayjs(container.dataset.date);
const endDate = dayjs(container.dataset.dateEnd);
const now = dayjs();

// 获取三个状态元素
const upcomingEl = container.querySelector('.state-upcoming');
const ongoingEl = container.querySelector('.state-ongoing');
const pastEl = container.querySelector('.state-past');

// 隐藏所有状态
upcomingEl.classList.add('hidden');
ongoingEl.classList.add('hidden');
pastEl.classList.add('hidden');

// 根据时间判断显示状态
if (now.isBefore(startDate)) {
upcomingEl.classList.remove('hidden');
}
else if (now.isAfter(endDate)) {
pastEl.classList.remove('hidden');
}
else {
ongoingEl.classList.remove('hidden');
}
});
});
</script>
</body>
</html>
```

### 实现原理说明:

1. **时间比较逻辑**:
- 使用`dayjs().isBefore()`判断当前时间是否在开始时间之前 → **未开始**
- 使用`dayjs().isAfter()`判断当前时间是否在结束时间之后 → **已结束**
- 中间状态自动视为 → **进行中**

2. **DOM操作流程**:
- 初始化时隐藏所有状态元素
- 根据时间条件移除对应元素的`hidden`类
- 使用`dataset`获取HTML5自定义属性值

3. **时间处理要点**:
- Day.js自动解析ISO格式日期(YYYY-MM-DD)
- 精确到日的比较(忽略具体时间)
- 自动处理时区差异(使用本地时区)

### 使用注意事项:
1. 确保引入Day.js库(已包含在代码中)
2. 日期格式必须为`YYYY-MM-DD`格式
3. 多个状态容器可同时处理
4. 状态样式可通过CSS自定义调整

此方案会自动根据服务器时间(用户本地时间)实时显示活动状态,无需刷新页面即可动态更新(页面加载时计算)。

total_tokens
3082