首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實戰 Day 9:jQuery 事件管理、Bootstrap 模態框封裝、Checkbox 全選難題與批量刪除實作

     編輯:PHP 相關知識

核心收穫速覽

  • 事件綁定去抖:動態綁定必須 .off() 或 .one(),否則重複觸發。
  • 模態框組件化:參數化標題、內容、按鈕文字、回調函數、傳遞數據,實現高復用。
  • Checkbox 全選陷阱:jQuery .attr('checked') vs .prop('checked')、DOM 原生 .checked 差異。
  • 批量刪除前後端協作:前端收集 ID 陣列 → AJAX POST → 後端事務處理 → 逐條返回結果。

一、模態框確認組件 showMsg()

HTML 模板(放入頁面底部)


<div id="msg" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 id="myModalLabel" class="modal-title"></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body"></div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
        <button id="msgConfirm" type="button" class="btn btn-danger"></button>
      </div>
    </div>
  </div>
</div>

JS 封裝(ES6 改寫,支援 Bootstrap 5)


/**
 * 通用確認模態框
 * @param {string} title - 標題
 * @param {string} content - 內容(支援 HTML)
 * @param {string} confirmText - 確認按鈕文字
 * @param {Function} onConfirm - 確認回調,接收 payload
 * @param {*} payload - 透傳給回調的數據
 */
function showMsg(title, content, confirmText, onConfirm, payload = null) {
    const modalEl = document.getElementById('msg');
    const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
    
    modalEl.querySelector('#myModalLabel').innerHTML = title;
    modalEl.querySelector('.modal-body').innerHTML = content;
    const btn = modalEl.querySelector('#msgConfirm');
    btn.textContent = confirmText;
    
    // 關鍵:先移除舊監聽器,防止重複綁定
    btn.replaceWith(btn.cloneNode(true)); // 核暴力解綁
    const newBtn = modalEl.querySelector('#msgConfirm');
    
    newBtn.addEventListener('click', () => {
        modal.hide();
        if (typeof onConfirm === 'function') onConfirm(payload);
    }, { once: true }); // {once:true} 自動解綁
    
    modal.show();
}

// 調用範例
showMsg('確認刪除', '此操作不可恢復', '刪除', (id) => {
    deleteContent(id);
}, 123);

二、自動消失的提示組件 showToast()


function showToast(message, type = 'success') {
    const alertClass = type === 'success' ? 'alert-success' : 'alert-danger';
    const html = `
        <div class="alert ${alertClass} alert-dismissible fade show" role="alert">
            ${message}
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        </div>`;
    $('#toastContainer').prepend(html); // 需頁面預留 #toastContainer
    
    // 3 秒自動關閉
    setTimeout(() => {
        $('.alert').first().alert('close');
    }, 3000);
}

三、Checkbox 全選/反選:避開 jQuery 陷阱

錯誤寫法(會失效)


// ❌ attr 僅操作 HTML 屬性,不影響 DOM property
$('#selectAll').click(() => $('input[name="ids[]"]').attr('checked', true));

正確寫法三種


// 1. prop(jQuery 1.6+ 推薦)
$('#selectAll').on('change', function() {
    $('input[name="ids[]"]').prop('checked', this.checked);
});

// 2. 原生 DOM 迭代(效能最佳、零依賴)
document.getElementById('selectAll').addEventListener('change', function() {
    document.querySelectorAll('input[name="ids[]"]').forEach(cb => cb.checked = this.checked);
});

// 3. 事件委派:行點擊切換該行 checkbox
$('#dataTable tbody').on('click', 'tr', function(e) {
    if (e.target.type === 'checkbox') return; // 避免雙重切換
    const cb = this.querySelector('input[type="checkbox"]');
    if (cb) cb.checked = !cb.checked;
});

四、批量刪除完整流程

前端:收集勾選 ID → POST 陣列


function batchDelete() {
    const ids = [...document.querySelectorAll('input[name="ids[]"]:checked')]
                .map(cb => cb.value);
    if (!ids.length) return showToast('請選擇項目', 'error');
    
    showMsg('批量刪除', `確定刪除 ${ids.length} 筆資料?`, '確定', () => {
        fetch('/admin/api/batch-delete', {
            method: 'POST',
            headers: {'Content-Type': 'application/json', 'X-CSRF-TOKEN': token},
            body: JSON.stringify({ ids })
        }).then(r => r.json()).then(res => {
            if (res.success) {
                showToast('刪除成功');
                setTimeout(() => location.reload(), 800);
            } else showToast(res.message || '失敗', 'error');
        });
    });
}

後端(Laravel 風格範例)


public function batchDelete(Request $request) {
    $ids = $request->json('ids', []);
    if (empty($ids)) return response()->json(['success' => false, 'message' => '空 ID']);
    
    $results = [];
    DB::transaction(function() use ($ids, &$results) {
        foreach ($ids as $id) {
            try {
                $deleted = Content::destroy($id);
                $results[] = ['id' => $id, 'state' => $deleted ? 'ok' : 'no'];
            } catch (\Exception $e) {
                $results[] = ['id' => $id, 'state' => 'no', 'error' => $e->getMessage()];
            }
        }
    });
    return response()->json(['success' => true, 'data' => $results]);
}

五、分頁與表格渲染優化建議

  • 使用 template 標籤或 JS 模板引擎(如 Handlebars)替代字串拼接。
  • 大數據量採用虛擬滾動或無限載入,避免一次性渲染數千行 tr。
  • 分頁元件抽離為獨立函數,支援 page_start/page_end/current 參數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved