如何从db.json删除动态创建卡片及绑定对应删除按钮
问题分析与解决方案
核心问题原因
- 空NodeList问题:你在
axios.get异步请求完成前就执行了document.querySelectorAll查询操作,此时动态卡片还未创建,自然获取不到任何元素,导致后续的事件绑定代码完全不执行。 - 删除按钮绑定错误:即使能拿到按钮,用循环索引
i+1作为删除的ID逻辑错误——索引和卡片实际ID并不总是匹配(比如删除中间卡片后,剩余卡片的索引和ID会错位),而且新增卡片重新渲染后,旧的事件监听会残留,引发重复执行问题。
解决方案步骤
1. 渲染前清空容器
每次调用getData渲染卡片前,先清空mainWrapper内容,避免重复生成卡片:
const getData = (data: Card[]) => { // 清空容器,避免重复渲染 mainWrapper.innerHTML = ''; data.forEach(obj => { // ... 原有创建卡片的代码 }); }
2. 直接为每个删除按钮绑定对应事件
在创建删除按钮时,直接利用当前卡片的obj.id绑定点击事件,确保每个按钮都对应正确的卡片:
// DELETE BUTTON const deleteBtn = document.createElement("button"); deleteBtn.classList.add("delete__btn"); deleteBtn.classList.add(`js-delete`); deleteBtn.innerHTML = "DELETE"; // 直接绑定事件,使用当前卡片的ID deleteBtn.addEventListener('click', () => { axios.delete(`http://localhost:3004/cards/${obj.id}`).then(({ data }) => { getData(data); }); }); btnSection.appendChild(deleteBtn);
3. 移除无效的事件绑定代码
删除原来的以下代码,因为它们在DOM元素生成前执行,完全无效:
let deleteButtons = document.querySelectorAll<HTMLButtonElement>(`.js-delete`) let editButtons = document.querySelectorAll<HTMLButtonElement>('.js-edit') let cards = document.querySelectorAll('.js-card') for (let i = 0; i < deleteButtons.length; i++) { deleteButtons[i].addEventListener('click', () => { axios.delete<Card[]>(`http://localhost:3004/cards/${i +1}`).then(({ data }) => { getData(data) }); }); }
修改后的完整TypeScript代码
import axios from 'axios'; const mainWrapper = document.querySelector('.js-main-wrapper') as HTMLDivElement type Card = { id: number, title: string, image: string, text: string } const getData = (data: Card[]) => { // 清空容器,避免重复渲染 mainWrapper.innerHTML = ''; data.forEach(obj => { // CARD const card = document.createElement("div"); card.classList.add("card"); card.classList.add("js-card"); mainWrapper.appendChild(card); // IMG-SECTION const imgSection = document.createElement("div"); imgSection.classList.add("img__section"); card.appendChild(imgSection); // TEXT-SECTION const txtSection = document.createElement("div"); txtSection.classList.add("text__section"); card.appendChild(txtSection); // BUTTON SECTION const btnSection = document.createElement("div"); btnSection.classList.add("btn__section"); card.appendChild(btnSection); // IMAGE const image = document.createElement("img") as HTMLImageElement image.classList.add("image"); image.src = `${obj.image}` imgSection.appendChild(image); // TITLE const title = document.createElement("h4"); title.classList.add("title"); title.innerHTML = `${obj.title}`; txtSection.appendChild(title); // TEXT const text = document.createElement("p"); text.classList.add("text"); text.innerHTML = `${obj.text}`; txtSection.appendChild(text); // EDIT BUTTON const editBtn = document.createElement("button"); editBtn.classList.add("edit__btn"); editBtn.classList.add("js-edit"); editBtn.innerHTML = "EDIT"; btnSection.appendChild(editBtn); // DELETE BUTTON const deleteBtn = document.createElement("button"); deleteBtn.classList.add("delete__btn"); deleteBtn.classList.add(`js-delete`); deleteBtn.innerHTML = "DELETE"; // 绑定对应卡片的删除事件 deleteBtn.addEventListener('click', () => { axios.delete(`http://localhost:3004/cards/${obj.id}`).then(({ data }) => { getData(data); }); }); btnSection.appendChild(deleteBtn); }); } axios.get<Card[]>('http://localhost:3004/cards').then(({ data }) => { getData(data); }) const addTitle = document.querySelector('.js-add-title') as HTMLInputElement const addText = document.querySelector('.js-add-text') as HTMLInputElement const addBtn = document.querySelector('.js-add-btn') // ADD NEW addBtn?.addEventListener('click', (e) => { // 阻止表单默认提交行为,避免页面刷新 e.preventDefault(); axios.post<Card[]>('http://localhost:3004/cards', { title: addTitle.value, text: addText.value, image: "https://picsum.photos/200", }).then(({ data }) => { getData(data); // 新增后清空输入框 addTitle.value = ''; addText.value = ''; }); });
额外补充:新增功能里添加e.preventDefault()阻止表单默认提交导致的页面刷新,同时新增后清空输入框提升用户体验。
内容的提问来源于stack exchange,提问作者Zixxy7
相关产品推荐
相关产品推荐

