
Easepick 的 PresetPlugin 默认在初始化时静态计算时间范围,导致“过去5分钟”等预设值始终基于页面加载时间。本文介绍通过 setup 钩子监听 select 事件,捕获预设触发行为并实时重置起止时间,实现真正“点击即生效”的动态预设。
easepick 的 presetplugin 默认在初始化时静态计算时间范围,导致“过去5分钟”等预设值始终基于页面加载时间。本文介绍通过 `setup` 钩子监听 `select` 事件,捕获预设触发行为并实时重置起止时间,实现真正“点击即生效”的动态预设。
在使用 Easepick 的 PresetPlugin 时,一个常见痛点是:预设范围(如 "past 5 minutes")在初始化时即被固化为两个 Date 实例,后续无论用户何时点击该预设,选取的始终是「页面加载时刻往前推5分钟」的时间段,而非「当前点击时刻往前推5分钟」——这严重违背用户直觉。
根本原因在于:customPreset 中的日期数组是初始化时一次性求值的静态快照,Easepick 并不支持动态函数式定义(如 () => [new Date(Date.now() - 5 * 60e3), new Date()])。但官方提供了 setup 生命周期钩子和丰富的事件系统,我们可借此实现“运行时矫正”。
✅ 核心思路:监听 select 事件 + 区分操作类型 + 动态重设
关键在于识别用户是点击了预设项(而非手动拖拽日历或输入框),然后立即用当前时间重新计算区间:
- 利用 setup(picker) 注册事件监听器:确保在 picker 实例就绪后绑定逻辑;
- 通过 event.target.innerHTML 粗略判断是否为预设点击(因 Easepick 未暴露更明确的事件源标识,此为实用折中方案;也可改用 event.detail?.presetKey 若版本支持);
- 提取原始跨度(end - start):保留用户选择的相对时长(如 5 分钟、3 小时);
- 调用 picker.setStartDate() 和 picker.setEndDate() 实时更新:以 new Date() 为基准,反向推算新起点。
以下是精简可靠的实现代码:
const minute = 60 * 1000;
const hour = 60 * minute;
const day = 24 * hour;
const picker = new easepick.create({
element: "#select_start",
css: ["https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css"],
format: "D MMM, HH:mm:ss",
grid: 2,
calendars: 2,
plugins: ["RangePlugin", "LockPlugin", "TimePlugin", "PresetPlugin"],
RangePlugin: {
elementEnd: "#select_end",
strict: false
},
LockPlugin: {
maxDate: new Date(),
minDate: new Date(Date.now() - 30 * day)
},
TimePlugin: {
seconds: true
},
PresetPlugin: {
position: 'left',
customPreset: {
"past 5 mins": [new Date(Date.now() - 5 * minute), new Date()],
"past 15 mins": [new Date(Date.now() - 15 * minute), new Date()],
"past 30 mins": [new Date(Date.now() - 30 * minute), new Date()],
"past 1 hour": [new Date(Date.now() - 1 * hour), new Date()],
"past 3 hours": [new Date(Date.now() - 3 * hour), new Date()],
"past 6 hours": [new Date(Date.now() - 6 * hour), new Date()],
"past 12 hours": [new Date(Date.now() - 12 * hour), new Date()]
}
},
// ? 关键:动态矫正逻辑入口
setup(picker) {
picker.on("select", (e) => {
// 判断是否为预设项点击(非手动选择)
if (!e.target?.innerHTML?.includes("selected")) {
const { start, end } = e.detail;
const spanMs = end - start; // 保持原始时间跨度
const now = new Date();
// 立即重设为「此刻往前推 spanMs」的新区间
picker.setStartDate(new Date(now.getTime() - spanMs));
picker.setEndDate(now);
}
});
}
});
⚠️ 注意事项与最佳实践
- 兼容性提示:上述 e.detail.start/end 在 Easepick v1.2+ 中稳定可用;若使用旧版,请检查 e.detail.dateStart/dateEnd。
- 避免重复触发:setStartDate/setEndDate 会再次触发 select 事件,因此需确保判断逻辑足够健壮(当前通过 DOM 文本判断已足够隔离)。
- 性能无负担:所有操作均为同步内存计算,无额外请求或渲染开销。
- 不可设 null 起止时间:Easepick 要求 start 和 end 均为有效 Date 对象;若需单边选择(如仅选开始时间),应改用 RangePlugin 的 onlyShowEnd 或切换为单选模式。
- CSS 加载建议:推荐使用完整 URL(如示例中的 @1.2.1)而非 @latest,避免因 CDN 缓存导致样式错乱。
通过这一方案,你无需重构整个日期选择流程,即可让所有预设时间范围真正“活”起来——每次点击,都是对当下时间的精准响应。











