在 ThinkPHP 框架下實作「不重新整理頁面即可刪除資料」的 AJAX 功能,是提升使用者體驗的關鍵技術。本文完整拆解從前端觸發、JS 請求、後端處理到前端回饋的完整流程。
用戶點擊「刪除」連結
↓
jQuery 綁定 click 事件 → 彈出確認對話框
↓
取得該筆資料的 ID (data-id 或 href 參數)
↓
發送 AJAX 請求到後端 Controller (JSON 格式)
↓
後端驗證權限 → 執行刪除 SQL → 回傳 JSON 結果
↓
前端接收回應 → 成功則移除 DOM 元素 / 失敗則提示錯誤
<!-- 列表項目 -->
<div class="list-item" data-id="<?php echo $val['id']; ?>">
<span><?php echo $val['title']; ?></span>
<a href="javascript:void(0);" class="delete-btn">刪除</a>
</div>
<script src="/Public/js/jquery.min.js"></script>
<script>
$(function() {
// 事件委派:適用於動態新增的元素
$(document).on('click', '.delete-btn', function(e) {
e.preventDefault();
var $btn = $(this);
var $item = $btn.closest('.list-item');
var id = $item.data('id'); // 從父層 data-id 取得
if (!confirm('確定要刪除這筆資料嗎?此操作無法復原。')) {
return;
}
// 視覺回饋:按鈕禁用 + 載入狀態
$btn.prop('disabled', true).text('刪除中...');
$.ajax({
url: '/Search/index.php/Jason/delete', // ThinkPHP URL 格式
type: 'POST', // 建議用 POST 執行刪除
data: { id: id },
dataType: 'json',
success: function(res) {
if (res.code === 1) { // 成功
// 動畫移除:slideUp 後再移除 DOM
$item.slideUp('normal', function() {
$(this).remove();
// 可選:檢查列表是否為空,顯示「無資料」提示
if ($('.list-item').length === 0) {
$('.list-container').html('<p class="empty">暫無資料</p>');
}
});
} else { // 失敗
alert('刪除失敗:' + (res.msg || '未知錯誤'));
$btn.prop('disabled', false).text('刪除');
}
},
error: function(xhr, status, error) {
console.error('AJAX 錯誤:', status, error);
alert('請求異常,請稍後再試');
$btn.prop('disabled', false).text('刪除');
}
});
});
});
</script>
<?php
class JasonAction extends Action {
public function delete() {
// 僅接受 POST 請求
if (!$this->isPost()) {
$this->ajaxReturn(['code' => 0, 'msg' => '請求方式錯誤']);
}
// 驗證用戶登入狀態
$userId = session('uid');
if (empty($userId)) {
$this->ajaxReturn(['code' => 0, 'msg' => '請先登入']);
}
// 取得並驗證 ID
$id = I('post.id', 0, 'intval');
if ($id <= 0) {
$this->ajaxReturn(['code' => 0, 'msg' => '參數錯誤']);
}
// 執行刪除 (假設模型名為 Article)
$model = M('Article'); // 或 D('Article') 若有邏輯層
$result = $model->where(['id' => $id, 'uid' => $userId])->delete();
// 注意:加上 uid 條件防止越權刪除他人資料
if ($result !== false) {
$this->ajaxReturn(['code' => 1, 'msg' => '刪除成功']);
} else {
$this->ajaxReturn(['code' => 0, 'msg' => '刪除失敗,資料不存在或無權限']);
}
}
}
?>
| 風險 | 防範措施 |
|---|---|
| CSRF 攻擊 | 表單加入 Token,AJAX 請求攜帶 Token 驗證 |
| 越權刪除 | SQL WHERE 條件加入擁有者 ID (uid) |
| ID 遍歷猜測 | 使用 UUID 或加密 ID,避免連續數字 ID |
| 誤刪無法復原 | 軟刪除 (status=0) 或備份表,提供回收站功能 |
| XSS 注入 | 輸出資料時使用 htmlspecialchars() 轉義 |
ids: [1,2,3]version 欄位,更新時檢查版本號防止併發衝突<?php
namespace Home\Controller;
use Think\Controller;
class JasonController extends Controller {
public function delete() {
if (!IS_POST) $this->ajaxReturn(['code'=>0, 'msg'=>'請求方式錯誤']);
$id = I('post.id', 0, 'intval');
$uid = session('uid');
$res = M('Article')->where(['id'=>$id, 'uid'=>$uid])->delete();
$this->ajaxReturn($res ? ['code'=>1] : ['code'=>0, 'msg'=>'刪除失敗']);
}
}
?>
'SHOW_PAGE_TRACE' => true 查看 SQL 日誌trace() 或 Log::write() 記錄關鍵變數console.log(res) 確認回傳結構