You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Watchlist功能异常:重复影片按钮状态无法同步更新

问题描述

我有一个影片列表,需求是用户点击「Add to my list」按钮时,将对应影片添加至数据库的watchlist表中。目前基础功能正常,但页面中存在重复影片条目,当用户点击添加按钮后,其他重复影片的按钮并未切换为「Remove from my list」状态。我需要实现所有重复影片的按钮同步切换状态,且仅向数据库添加一条记录(如图中黄色圈出的按钮也需切换为「Remove from My List」)。

原代码

const buttons = document.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    e.preventDefault();
    if (btn.dataset.add) {
      // Call add item
      addItemToDB(btn);
    } else {
      // Call remove item
      removeItemFromDB(btn);
    }
  });

  checkItemExist(btn).then((itemExist) => {
    if (itemExist) {
      btn.parentElement.innerHTML = `<button onclick="removeItemFromDB(this)" data-add="false" class="remove-from-watchlist-btn">Remove from My List</button>`;
    }
  });
});

async function addItemToDB(btn) {
  // Check if item exist in DB
  checkItemExist(btn).then(async (itemExist) => {
    if (!itemExist) {
      //  Add Item
      let formData = new FormData();
      formData.append("itemId", btn.parentElement.parentElement.dataset.id);
      formData.append(
        "itemName",
        btn.parentElement.previousElementSibling.dataset.name
      );
      formData.append(
        "itemPoster",
        btn.parentElement.parentElement.firstElementChild.dataset.poster
      );

      const response = await fetch("request/addItem.php", {
        method: "POST",
        body: formData,
      });

      const result = await response.json();

      if (result) {
        btn.parentElement.innerHTML = `<button onclick="removeItemFromDB(this)" data-add="false" class="remove-from-watchlist-btn">Remove from My List</button>`;
      }
    } else {
      console.log("Item exist");
    }
  });
}

async function removeItemFromDB(btn) {
  checkItemExist(btn).then(async (itemExist) => {
    if (itemExist) {
      let formData = new FormData();
      formData.append("itemId", btn.parentElement.parentElement.dataset.id);
      formData.append(
        "itemName",
        btn.parentElement.previousElementSibling.dataset.name
      );

      const response = await fetch("request/removeItem.php", {
        method: "POST",
        body: formData,
      });

      const result = await response.json();
      if (result) {
        btn.parentElement.innerHTML = `<button onclick="addItemToDB(this)" data-add="true" class="add-to-watchlist-btn">Add to My List</button>`;
      }
    }
  });
}

async function checkItemExist(btn) {
  let formData = new FormData();
  formData.append("itemId", btn.parentElement.parentElement.dataset.id);
  formData.append(
    "itemName",
    btn.parentElement.previousElementSibling.dataset.name
  );

  const response = await fetch("request/itemExist.php", {
    method: "POST",
    body: formData,
  });

  const result = await response.json();
  if (result) return true;
  else return false;
}
解决方案

核心逻辑是通过影片ID批量操作所有同影片的按钮,避免只更新当前点击的按钮。以下是具体修改:

1. 新增批量更新按钮状态的函数

创建updateAllMovieButtons函数,根据影片ID找到所有对应容器,统一替换按钮:

function updateAllMovieButtons(itemId, isAdded) {
  // 找到所有同ID的影片容器
  const movieContainers = document.querySelectorAll(`[data-id="${itemId}"]`);
  movieContainers.forEach(container => {
    const btnContainer = container.querySelector('button').parentElement;
    if (isAdded) {
      btnContainer.innerHTML = `<button data-add="false" class="remove-from-watchlist-btn">Remove from My List</button>`;
    } else {
      btnContainer.innerHTML = `<button data-add="true" class="add-to-watchlist-btn">Add to My List</button>`;
    }
  });
}

2. 重构增删函数,改用批量更新

去掉嵌套Promise,改用async/await简化逻辑,并在操作成功后调用批量更新函数:

修改后的addItemToDB

async function addItemToDB(btn) {
  const itemId = btn.parentElement.parentElement.dataset.id;
  const itemExist = await checkItemExist(btn);
  
  if (!itemExist) {
    const itemName = btn.parentElement.previousElementSibling.dataset.name;
    const itemPoster = btn.parentElement.parentElement.firstElementChild.dataset.poster;
    
    let formData = new FormData();
    formData.append("itemId", itemId);
    formData.append("itemName", itemName);
    formData.append("itemPoster", itemPoster);

    const response = await fetch("request/addItem.php", {
      method: "POST",
      body: formData,
    });

    const result = await response.json();

    if (result) {
      updateAllMovieButtons(itemId, true);
    }
  } else {
    console.log("Item exist");
  }
}

修改后的removeItemFromDB

async function removeItemFromDB(btn) {
  const itemId = btn.parentElement.parentElement.dataset.id;
  const itemExist = await checkItemExist(btn);
  
  if (itemExist) {
    const itemName = btn.parentElement.previousElementSibling.dataset.name;
    
    let formData = new FormData();
    formData.append("itemId", itemId);
    formData.append("itemName", itemName);

    const response = await fetch("request/removeItem.php", {
      method: "POST",
      body: formData,
    });

    const result = await response.json();
    if (result) {
      updateAllMovieButtons(itemId, false);
    }
  }
}

3. 初始化逻辑优化

用事件委托绑定点击事件(避免动态生成按钮丢失绑定),并批量初始化同ID影片的按钮状态,减少重复请求:

async function initWatchlistButtons() {
  // 收集唯一影片ID,避免重复请求
  const uniqueMovieIds = new Set();
  document.querySelectorAll('[data-id]').forEach(container => {
    uniqueMovieIds.add(container.dataset.id);
  });

  // 批量初始化每个影片的按钮状态
  for (const itemId of uniqueMovieIds) {
    const firstBtn = document.querySelector(`[data-id="${itemId}"] button`);
    if (firstBtn) {
      const itemExist = await checkItemExist(firstBtn);
      updateAllMovieButtons(itemId, itemExist);
    }
  }

  // 事件委托绑定点击事件
  document.addEventListener('click', (e) => {
    const btn = e.target.closest('button');
    if (!btn) return;
    
    e.preventDefault();
    if (btn.dataset.add === 'true') {
      addItemToDB(btn);
    } else {
      removeItemFromDB(btn);
    }
  });
}

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initWatchlistButtons);
完整修改后代码
// 批量更新同ID影片的按钮状态
function updateAllMovieButtons(itemId, isAdded) {
  const movieContainers = document.querySelectorAll(`[data-id="${itemId}"]`);
  movieContainers.forEach(container => {
    const btnContainer = container.querySelector('button').parentElement;
    if (isAdded) {
      btnContainer.innerHTML = `<button data-add="false" class="remove-from-watchlist-btn">Remove from My List</button>`;
    } else {
      btnContainer.innerHTML = `<button data-add="true" class="add-to-watchlist-btn">Add to My List</button>`;
    }
  });
}

// 检查影片是否已在列表中
async function checkItemExist(btn) {
  const itemId = btn.parentElement.parentElement.dataset.id;
  const itemName = btn.parentElement.previousElementSibling.dataset.name;
  
  let formData = new FormData();
  formData.append("itemId", itemId);
  formData.append("itemName", itemName);

  const response = await fetch("request/itemExist.php", {
    method: "POST",
    body: formData,
  });

  const result = await response.json();
  return Boolean(result);
}

// 添加影片到列表
async function addItemToDB(btn) {
  const itemId = btn.parentElement.parentElement.dataset.id;
  const itemExist = await checkItemExist(btn);
  
  if (!itemExist) {
    const itemName = btn.parentElement.previousElementSibling.dataset.name;
    const itemPoster = btn.parentElement.parentElement.firstElementChild.dataset.poster;
    
    let formData = new FormData();
    formData.append("itemId", itemId);
    formData.append("itemName", itemName);
    formData.append("itemPoster", itemPoster);

    const response = await fetch("request/addItem.php", {
      method: "POST",
      body: formData,
    });

    const result = await response.json();

    if (result) {
      updateAllMovieButtons(itemId, true);
    }
  } else {
    console.log("Item exist");
  }
}

// 从列表移除影片
async function removeItemFromDB(btn) {
  const itemId = btn.parentElement.parentElement.dataset.id;
  const itemExist = await checkItemExist(btn);
  
  if (itemExist) {
    const itemName = btn.parentElement.previousElementSibling.dataset.name;
    
    let formData = new FormData();
    formData.append("itemId", itemId);
    formData.append("itemName", itemName);

    const response = await fetch("request/removeItem.php", {
      method: "POST",
      body: formData,
    });

    const result = await response.json();
    if (result) {
      updateAllMovieButtons(itemId, false);
    }
  }
}

// 初始化页面
async function initWatchlistButtons() {
  // 收集唯一影片ID,避免重复请求
  const uniqueMovieIds = new Set();
  document.querySelectorAll('[data-id]').forEach(container => {
    uniqueMovieIds.add(container.dataset.id);
  });

  // 批量初始化每个影片的按钮状态
  for (const itemId of uniqueMovieIds) {
    const firstBtn = document.querySelector(`[data-id="${itemId}"] button`);
    if (firstBtn) {
      const itemExist = await checkItemExist(firstBtn);
      updateAllMovieButtons(itemId, itemExist);
    }
  }

  // 事件委托绑定点击事件
  document.addEventListener('click', (e) => {
    const btn = e.target.closest('button');
    if (!btn) return;
    
    e.preventDefault();
    if (btn.dataset.add === 'true') {
      addItemToDB(btn);
    } else {
      removeItemFromDB(btn);
    }
  });
}

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initWatchlistButtons);

内容的提问来源于stack exchange,提问作者Tony Vito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 09:36:10