当前位置: 首页 > news >正文

全局计时器、智能提醒与UI交互实现

本文分享「灶台导航」小程序中多菜谱烹饪的运行机制,包括全局计时器设计、智能提醒触发逻辑以及页面交互的完整实现。


一、全局计时器实现

1.1 计时器完整代码

这个计时器类支持开始、暂停、继续、停止,并且支持注册多个回调函数:

/** * 多菜谱全局计时器 * 核心功能:统一时间基准、支持暂停/继续、每秒通知所有监听者 */ class GlobalCookTimer { constructor() { this.startTime = null // 开始时间戳(毫秒) this.elapsedTime = 0 // 已经过的秒数 this.intervalId = null // 定时器ID this.isRunning = false // 是否运行中 this.isPaused = false // 是否暂停中 this.pauseTime = 0 // 暂停时的时间戳 this.callbacks = [] // 回调函数列表 } /** * 开始计时 */ start() { this.startTime = Date.now() this.isRunning = true this.isPaused = false this.intervalId = setInterval(() => { this.tick() }, 1000) } /** * 暂停 */ pause() { if (!this.isRunning || this.isPaused) return this.isPaused = true this.pauseTime = Date.now() clearInterval(this.intervalId) }
/** * 继续(核心:补偿暂停时间) * 原理:startTime 向后移动 pauseDuration,仿佛暂停从未发生 */ resume() { if (!this.isPaused) return // 计算暂停了多久 const pauseDuration = Date.now() - this.pauseTime // 调整开始时间,补偿暂停时长 this.startTime += pauseDuration this.isPaused = false this.intervalId = setInterval(() => { this.tick() }, 1000) } /** * 停止 */ stop() { clearInterval(this.intervalId) this.isRunning = false this.isPaused = false }
/** * 每秒执行一次,更新经过时间并通知回调 */ tick() { this.elapsedTime = Math.floor((Date.now() - this.startTime) / 1000) this.callbacks.forEach(cb => cb(this.elapsedTime)) } /** * 注册回调 */ onTick(callback) { this.callbacks.push(callback) }
/** * 获取当前时间(支持暂停时正确返回) */ getElapsed() { if (this.isPaused) { return Math.floor((this.pauseTime - this.startTime) / 1000) } return Math.floor((Date.now() - this.startTime) / 1000) } /** * 销毁 */ destroy() { this.stop() this.callbacks = [] } }

1.2 暂停补偿原理图解

用户暂停10分钟的场景: 暂停前: startTime = 12:00:00 当前经过时间 = 300秒 当前真实时间 = 12:05:00 用户点击暂停,10分钟后点击继续: 暂停时长 = 600秒 新startTime = 12:00:00 + 600 = 12:10:00 恢复后计算经过时间: 当前真实时间 = 12:15:00 经过时间 = 12:15:00 - 12:10:00 = 300秒 ✅ 效果:仿佛那10分钟从未存在过,计时器继续从300秒开始

1.3 页面集成代码

// pages/cook/cook.js Page({ data: { schedule: null, elapsedSeconds: 0, currentTasks: [], completedSteps: [] }, globalTimer: null, onLoad(options) { const recipeIds = JSON.parse(options.recipes || '[]') this.loadAndCalculate(recipeIds) }, onUnload() { // 页面销毁时清理计时器,防止内存泄漏 if (this.globalTimer) { this.globalTimer.destroy() } }, async loadAndCalculate(recipeIds) { const recipes = await this.loadRecipes(recipeIds) const schedule = calculateSchedule(recipes) this.setData({ schedule }) this.initTimer(schedule) }, initTimer(schedule) { this.globalTimer = new GlobalCookTimer() this.globalTimer.onTick((elapsed) => { this.onTimerTick(elapsed) }) this.globalTimer.start() }, onTimerTick(elapsed) { const { schedule } = this.data this.setData({ elapsedSeconds: elapsed }) // 获取当前应该执行的任务 const currentTasks = this.getCurrentTasks(elapsed) if (currentTasks.length > 0) { this.setData({ currentTasks }) this.checkNewTasks(currentTasks) } this.checkCompletedTasks(elapsed) // 检查是否全部完成 if (elapsed >= schedule.totalDuration) { this.onAllComplete() } }, /** * 获取当前时间点正在进行的任务 * 核心逻辑:判断 elapsed 是否在步骤的 [start, end) 区间内 */ getCurrentTasks(elapsed) { const tasks = [] this.data.schedule.recipes.forEach(recipe => { recipe.steps.forEach(step => { if (elapsed >= step.globalStartTime && elapsed < step.globalEndTime) { tasks.push({ recipeId: recipe.recipeId, recipeName: recipe.recipeName, step, remaining: step.globalEndTime - elapsed // 剩余秒数 }) } }) }) return tasks } })

二、提醒机制实现

2.1 提醒管理器完整代码

/** * 提醒管理器 * 功能:检测关键节点,触发语音提醒,防止重复提醒 */ class ReminderManager { constructor(ttsQueue) { this.ttsQueue = ttsQueue // 语音队列,处理异步播放 this.reminded = new Set() // 已提醒过的任务ID,用于去重 } /** * 检查是否需要提醒(每秒调用一次) */ check(elapsed, schedule) { // 检查即将开始的任务(提前30秒提醒) schedule.timeline.forEach(event => { if (event.type === 'start') { const timeToStart = event.time - elapsed if (timeToStart > 0 && timeToStart <= 30 && !this.reminded.has(`start-${event.time}`)) { this.reminded.add(`start-${event.time}`) this.remindTaskStart(event) } } }) // 检查即将结束的任务(提前10秒提醒) schedule.timeline.forEach(event => { if (event.type === 'end') { const timeToEnd = event.time - elapsed if (timeToEnd > 0 && timeToEnd <= 10 && !this.reminded.has(`end-${event.time}`)) { this.reminded.add(`end-${event.time}`) this.remindTaskEnd(event) } } }) } remindTaskStart(event) { const text = `${event.recipeName}即将开始第${event.step.order}步` this.ttsQueue.add(text) } remindTaskEnd(event) { const text = `${event.recipeName}第${event.step.order}步即将完成` this.ttsQueue.add(text) } reset() { this.reminded.clear() } }

2.2 提前量设计说明

提醒类型提前量设计原因
任务开始30秒给用户30秒准备时间,比如洗手、拿食材
任务结束10秒防止烧干锅,10秒足够用户走到灶台前
剩余时间10分钟/5分钟/1分钟整点提醒,让用户把握整体进度

2.3 周期性时间提醒

/** * 周期性时间提醒 * 在关键剩余时间点提醒用户 */ function setupPeriodicReminder(timer, schedule) { // 关键时间节点(秒):10分钟、5分钟、1分钟、30秒、10秒 const reminderPoints = [600, 300, 60, 30, 10] const reminded = new Set() timer.onTick(elapsed => { const remaining = schedule.totalDuration - elapsed reminderPoints.forEach(point => { // 当剩余时间首次小于等于某个节点时触发提醒 if (remaining <= point && remaining > point - 5 && !reminded.has(point)) { reminded.add(point) announceRemaining(remaining) } }) }) } function announceRemaining(seconds) { let text if (seconds >= 600) { text = `还有${Math.floor(seconds / 60)}分钟` } else if (seconds >= 60) { text = `还有${Math.floor(seconds / 60)}分钟` } else { text = `还有${seconds}秒` } ttsQueue.add(text) }

三、UI 展示

3.1 页面模板代码

<!-- 多菜谱烹饪页面 --> <view class="multi-cook-container"> <!-- 时间概览 --> <view class="time-overview"> <text class="elapsed">{{elapsedDisplay}}</text> <text class="total">/ {{totalDurationDisplay}}</text> </view> <!-- 进度条 --> <view class="progress-bar"> <view class="progress-fill" style="width: {{progress}}%"></view> </view> <!-- 当前任务列表 --> <view class="current-tasks"> <view class="task-card" wx:for="{{currentTasks}}" wx:key="recipeId"> <view class="task-header"> <text class="recipe-name">{{item.recipeName}}</text> <text class="step-label">步骤 {{item.step.order}}</text> </view> <view class="task-content">{{item.step.content}}</view> <view class="task-footer"> <text class="remaining">剩余 {{item.remaining}}秒</text> </view> </view> </view> <!-- 控制按钮 --> <view class="controls"> <button wx:if="{{!isPaused}}" bindtap="onPause">暂停</button> <button wx:if="{{isPaused}}" bindtap="onResume">继续</button> </view> </view>

3.2 UI 交互说明

UI 元素数据绑定更新频率作用
时间概览elapsedDisplay每秒让用户知道当前进度
进度条progress%每秒视觉化整体进度
任务卡片currentTasks任务变化时显示当前该做什么
剩余时间remaining每秒紧迫感提示
控制按钮isPaused点击时暂停/继续计时

3.3 任务卡片显示逻辑

  • 可以显示多个卡片:比如红烧肉在炖(wait类型),同时番茄蛋汤在准备(cook类型),两个任务可以并行

  • 剩余时间倒计时:每秒递减,让用户感知紧迫程度

  • 完成任务自动移除:当 elapsed >= globalEndTime 时,该任务卡片消失


四、总结

模块核心职责关键代码设计要点
全局计时器统一时间基准,支持暂停GlobalCookTimer 类暂停补偿算法
任务检测实时判断当前该做什么getCurrentTasks()区间比较 + 状态机
提醒机制关键节点语音播报ReminderManager 类提前量 + 去重队列
UI交互信息展示与用户控制WXML + 数据绑定多任务卡片 + 进度条

整套系统让用户可以"无脑"跟着指引走,系统自动告诉你接下来该做什么、什么时候做、还剩多久,大大降低了多菜同时烹饪的心智负担。

http://www.zskr.cn/news/1513488.html

相关文章:

  • Quake3e:现代图形API如何重塑经典竞技场引擎的技术架构
  • 解密Apollo配置中心的高可用设计:从长轮询到本地缓存,你的配置真的安全吗?
  • 2026携号转网API选型全指南:直连接口、代码示例与生产环境踩坑实录
  • Typora插件终极指南:70+免费功能让Markdown写作效率提升300%
  • 大模型长文本摘要能力压测:资源驱动的书籍摘要方法论
  • 轻量级可信计算-望获OS的安全启动方案
  • 运筹优化面试必考:单纯形法从几何到代数的核心思想与常见坑点解析
  • **采集节点主备模:保障监控系统自身高可用**
  • 思源宋体TTF:7种字重免费商用中文解决方案
  • 2026 手机号黑名单检测 API 选型指南:技术指标、服务商对比与生产环境落地
  • 2026汕头买房必看:选择汕头房产中介公司的注意事项! - 企业品牌
  • Linux Schedutil 的 freq_update_needed:调频触发条件判断
  • 2026成都二手房装修公司实力排名:5000+业主实测数据版 - 推荐官
  • Win11Debloat:Windows系统性能优化引擎的技术解析与实践指南
  • 2026如何选择最好的汕头房产中介公司?避免购房陷阱! - 企业品牌
  • MC9S12XB微控制器:XGATE协处理器与低功耗设计实战解析
  • “老照片修复”免费开源神器!支持高清批量修复!图片总是不够清晰?轻松把模糊的图片变清晰的AI软件!图片无损放大神器!
  • Python周刊2026W23 | Polars 1.41、PyPy v7.3.23、Python 3.15、httpx2、dj-lite-tenant
  • 重庆挂机空调不制冷维修,1小时内上门就找一步到家 - 不与人计较
  • GitHub Profile美化(1)
  • 2026年TOP10口碑最佳Geo服务机构揭晓,谁是行业领头羊? - 轩铭卿
  • 淘宝自动化脚本终极指南:如何每天自动赚取淘金币,节省30分钟宝贵时间
  • 2026年职场进阶提升路径:避坑指南好找工作的证考试难度与系统方法解析
  • 2026汕头房产中介公司如何选?看完这5个秘诀再决定! - 企业品牌
  • 5分钟快速上手:asmr-downloader让你的ASMR音频下载效率提升10倍
  • 收藏!小白程序员必看:如何抓住AI大模型红利,轻松入局高薪赛道?
  • AI Agent工具链生态全景图:2026年核心组件与集成方案
  • “[13-1]PWR电源控制
  • 大模型加Excel:自动分析表格数据
  • 硬件安全处理器MPC184架构解析与嵌入式系统集成实战