如何在CodeIgniter中用setInterval+Ajax自动显示Modal并更新数据?
问题
我想在时间到期时为所有用户弹出提醒弹窗,目前设置了当剩余天数、小时数、分钟数均为0时触发Modal和setInterval,但代码完全不起作用:Modal无法自动显示,必须刷新页面才可能出现,而且数据也无法更新。请问该怎么实现这个功能?
现有视图代码
<form action="<?php echo base_url(); ?>submissions/lock" id="btnexp" method="post"> <input type="hidden" value="<?php echo $period['period_id']; ?>" name="period_id"> <?php if($period['duration']!='0000-00-00 00:00:00'): ?> <?php date_default_timezone_set('Asia/Manila'); $datetime = date("Y-m-d H:i:s"); $date1 = new DateTime($datetime); $date2 = new DateTime($period['duration']); $interval = $date1->diff($date2); $days = $interval->days; $hours = $interval->h; $min = $interval->i; // echo $interval->format("%Y-%m-%d %H:%i:%s").'<br>'; // shows the total amount of days (not divided into years, months and days like above) $interval->days; $interval->h; $interval->i; if($days == 0 && $hours == 0 && $min == 0){ ?> <script> $(function(){ //function setInterval(function(){ $.ajax({ type: 'POST', url: '<?php echo base_url() ?>submissions/lock', async:false, cache: false, success: function(data){ if (data == 0){ $('#myModal').modal('show'); } }, error: function(){ alert('Could not get Data from Database'); } }); }, 1000); }); </script> <?php } ?> <?php endif; ?> </form>
现有控制器代码(Submissions/Lock)
public function lock() { $this->submission_model->lock(); }
问题分析与解决方案
核心问题
- 服务器端判断仅执行一次:只有用户加载页面时刚好处于到期时刻,才会插入弹窗脚本;如果页面加载后时间才到期,脚本根本不会被渲染,自然无法触发。
- 控制器无返回值:
lock方法只执行了模型逻辑,但没有输出任何响应数据,前端AJAX的success回调里data == 0的判断永远不成立,Modal不会显示。 - 定时器效率低下:每秒发起一次AJAX请求,会造成不必要的服务器压力。
- 同步AJAX阻塞浏览器:
async:false会阻塞页面其他操作,影响用户体验。
修正步骤
1. 前端实时监控到期时间
把服务器端的到期时间传递给JS,前端计算距离到期的剩余时间,到点后直接触发弹窗并调用锁定接口,无需每秒轮询。
修改后的视图代码:
<form action="<?php echo base_url(); ?>submissions/lock" id="btnexp" method="post"> <input type="hidden" value="<?php echo $period['period_id']; ?>" name="period_id"> <?php if($period['duration']!='0000-00-00 00:00:00'): ?> <script> $(function(){ // 获取服务器端的到期时间(转换为时间戳) const expiryTime = new Date("<?php echo $period['duration']; ?>").getTime(); const now = new Date().getTime(); const timeDiff = expiryTime - now; // 如果已经到期,直接弹窗 if(timeDiff <= 0){ showExpiryModal(); } else { // 设置定时器,到期时触发 setTimeout(() => { showExpiryModal(); }, timeDiff); } function showExpiryModal(){ // 调用锁定接口 $.ajax({ type: 'POST', url: '<?php echo base_url() ?>submissions/lock', cache: false, success: function(data){ // 不管接口返回什么,直接弹窗(或根据返回值判断) $('#myModal').modal('show'); }, error: function(){ alert('无法连接服务器'); } }); } }); </script> <?php endif; ?> </form>
2. 修改控制器返回响应数据
让lock方法执行完模型逻辑后,输出响应内容,方便前端判断:
public function lock() { // 执行锁定逻辑 $result = $this->submission_model->lock(); // 根据执行结果返回数据,比如成功返回1,失败返回0 echo $result ? 1 : 0; // 或者返回JSON格式 // echo json_encode(['status' => $result ? 'success' : 'failed']); }
3. 可选:实现全局实时提醒(针对所有用户)
如果需要让所有在线用户都能实时收到到期提醒,仅靠前端定时器不够(比如用户打开页面后,到期时间被后台修改),可以结合WebSocket或者长轮询实现,但这会增加复杂度。如果需求不严格,前端定时检查(比如每30秒一次)也可以接受,修改前端定时器为:
// 每30秒检查一次到期状态 setInterval(() => { $.ajax({ type: 'GET', url: '<?php echo base_url() ?>submissions/check_expiry', data: {period_id: <?php echo $period['period_id']; ?>}, success: function(data){ if(data == 'expired'){ $('#myModal').modal('show'); // 弹窗后清除定时器,避免重复触发 clearInterval(this); } } }); }, 30000);
同时新增一个check_expiry控制器方法,用于检查当前时间段是否到期:
public function check_expiry() { $period_id = $this->input->get('period_id'); $period = $this->submission_model->get_period($period_id); date_default_timezone_set('Asia/Manila'); $now = new DateTime(); $expiry = new DateTime($period['duration']); if($now >= $expiry){ echo 'expired'; } else { echo 'active'; } }
内容的提问来源于stack exchange,提问作者Coder Codes
相关产品推荐
相关产品推荐

