如何让Telegram Bot仅点击按钮才依次展示内容,避免循环一次性全发
实现分步展示消息的解决方案
核心思路
- 提前过滤所有符合条件的职位,不要在循环里直接发送消息
- 给每个用户维护独立的浏览状态:待展示职位列表、当前浏览的索引位置
- 新增「下一条」回调按钮,通过按钮点击事件触发下一条消息的发送,替代原有的一次性循环发送逻辑
代码实现示例
首先定义用户状态存储结构(生产环境可替换为Redis、数据库等持久化存储):
# 存储每个用户的职位浏览状态,key为用户chat_id,value为{'jobs': 匹配的职位列表, 'index': 当前浏览索引} user_job_state = {}
替换原有循环发送的逻辑:
# 第一步:先过滤出所有符合条件的职位 matched_jobs = [] for job in jobs: # 原有条件存在运算符优先级问题,已为性别判断增加括号修正逻辑 if int(job[6]) <= int(user.dpr) and int(job[7]) <= int(user.profil) and (job[4] == user.sex or job[5] == user.sex): matched_jobs.append(job) # 存储用户状态 chat_id = message.chat.id user_job_state[chat_id] = { 'jobs': matched_jobs, 'index': 0 } # 第二步:发送第一条职位(如果有匹配结果) if not matched_jobs: bot.send_message(chat_id, "暂无符合条件的职位") else: # 生成带跳转按钮和下一条按钮的键盘 def gen_first_markup(job): markup = InlineKeyboardMarkup() markup.row_width = 1 markup.add(InlineKeyboardButton(text='לאתר מתגייסים', url=job[3])) # 只有不止一个职位的时候才加下一条按钮 if len(matched_jobs) > 1: markup.add(InlineKeyboardButton(text='下一个职位', callback_data='next_job')) return markup first_job = matched_jobs[0] bot.send_message(chat_id, f"<b>{first_job[1]}</b>\n{first_job[2]}", reply_markup=gen_first_markup(first_job), parse_mode='HTML')
新增「下一个职位」回调事件处理逻辑:
# 处理「下一个职位」的回调事件 @bot.callback_query_handler(func=lambda call: call.data == 'next_job') def handle_next_job(call): chat_id = call.message.chat.id # 检查用户有没有待浏览的职位 if chat_id not in user_job_state: bot.answer_callback_query(call.id, "请先触发职位查询") return state = user_job_state[chat_id] next_index = state['index'] + 1 total = len(state['jobs']) # 已经到最后一条 if next_index >= total: bot.answer_callback_query(call.id, "已经是最后一个职位了") return # 更新索引 state['index'] = next_index current_job = state['jobs'][next_index] # 生成当前职位的键盘 def gen_current_markup(): markup = InlineKeyboardMarkup() markup.row_width = 1 markup.add(InlineKeyboardButton(text='לאתר מתגייסים', url=current_job[3])) # 还有下一条才加下一条按钮 if next_index < total - 1: markup.add(InlineKeyboardButton(text='下一个职位', callback_data='next_job')) return markup # 发送新的职位消息 bot.send_message(chat_id, f"<b>{current_job[1]}</b>\n{current_job[2]}", reply_markup=gen_current_markup(), parse_mode='HTML') # 回应对调请求 bot.answer_callback_query(call.id)
注意事项
- 原代码的筛选逻辑存在运算符优先级问题,
and优先级高于or,会导致性别筛选逻辑不符合预期,示例代码中已经为性别判断条件增加了括号修正逻辑 - 如果需要支持多用户同时使用,不要用全局变量存储状态,生产环境建议使用Redis、数据库等持久化存储用户浏览状态
- 如果需要支持用户退出后重新进入还能接着看,可以把状态存储到用户表对应的字段里
- 回调数据如果需要区分不同的查询场景,可以在callback_data里加额外标识,避免和其他回调事件冲突
内容的提问来源于stack exchange,提问作者Floyd1337
相关产品推荐
相关产品推荐

