点击卡牌图片添加对应卡牌框至卡组列表的实现方案咨询
点击卡牌图片添加对应卡牌框至卡组列表的实现方案咨询
嘿,你的思路方向是对的,算是不错的起步,但确实有几个地方需要调整,才能实现你想要的功能——比如匹配对应卡牌、跟踪数量,还有后续的动画效果。咱们一步步来梳理改进点:
1. 先解决「点击对应卡牌添加对应卡组项」的核心问题
你现在的代码里,addItem函数用document.querySelector(".card-body")只会选中页面中第一个.card-body元素,所以不管点哪个按钮,都会添加同一张卡牌的框架。另外还有个隐藏问题:你的HTML里有重复的id="box"和id="Cat1",这不符合HTML规范(id必须唯一),会导致后续JS选择器出错。
改进方案:
- 给每个ADD按钮传递对应卡牌的标识(比如名称),让函数知道要添加哪张卡
- 把卡组列表的容器改成唯一id,移除重复的id属性
- 修改
addItem函数,根据标识匹配对应的卡牌模板
修改后的代码示例:
HTML部分(调整按钮和卡组容器)
<div class="container"> <div class="card-image"> <img src="https://placehold.co/200x300/blue/white?text=Aeito" alt="Aeito"> <button onclick="addItem('Aeito')">ADD!</button> </div> <div class="card-image"> <img src="https://placehold.co/200x300/orange/white?text=Scipius" alt="Scipius"> <button onclick="addItem('Scipius')">ADD!</button> </div> <div class="card-frame"> <!-- 唯一的卡组列表容器 --> <div id="deck-list"> <!-- 模板卡片(可以隐藏,只做克隆用) --> <div class="card template" style="display:none;"> <div class="card-body" data-card="Aeito"> <h5 class="card-title">Aeito</h5> <img src="https://placehold.co/200x300/blue/white?text=Aeito" alt=""> </div> </div> <div class="card template" style="display:none;"> <div class="card-body" data-card="Scipius"> <h5 class="card-title">Scipius</h5> <img src="https://placehold.co/200x300/orange/white?text=Scipius" alt=""> </div> </div> </div> </div> </div>
JS部分(匹配对应卡牌并克隆)
function addItem(cardName) { // 根据卡牌名称找到对应的模板 const template = document.querySelector(`.card-body[data-card="${cardName}"]`); // 克隆模板元素 const clone = template.cloneNode(true); // 添加到卡组列表 document.getElementById("deck-list").appendChild(clone); }
2. 实现「跟踪卡牌数量」的功能
要避免重复添加相同卡牌的框架,而是更新数量,可以用一个对象来记录每张卡的数量,每次点击时判断卡组中是否已有该卡牌:
改进方案:
- 给卡牌框架添加数量显示元素
- 用全局对象记录数量,点击时更新数量或添加新卡牌
修改后的代码示例:
HTML模板(添加数量元素)
<div class="card-body" data-card="Aeito"> <h5 class="card-title">Aeito</h5> <span class="card-count">x1</span> <img src="https://placehold.co/200x300/blue/white?text=Aeito" alt=""> </div>
JS部分(跟踪并更新数量)
// 初始化卡牌数量记录 const cardQuantity = { Aeito: 0, Scipius: 0 }; function addItem(cardName) { const deckList = document.getElementById("deck-list"); // 检查卡组中是否已有该卡牌 const existingCard = deckList.querySelector(`.card-body[data-card="${cardName}"]`); if (existingCard) { // 已有该卡牌,更新数量 cardQuantity[cardName]++; existingCard.querySelector(".card-count").textContent = `x${cardQuantity[cardName]}`; } else { // 没有该卡牌,克隆模板并添加 const template = document.querySelector(`.card-body[data-card="${cardName}"]`); const clone = template.cloneNode(true); cardQuantity[cardName] = 1; deckList.appendChild(clone); } }
3. 用GSAP实现「卡牌移动到卡组」的动画效果
要实现动画,核心思路是创建一个和原卡牌一模一样的“幽灵元素”,用GSAP驱动它从原位置动画到卡组位置,动画结束后再更新卡组:
示例代码:
function addItem(cardName) { // 获取原卡牌的位置和元素 const sourceCard = document.querySelector(`.card-image img[alt="${cardName}"]`); // 创建幽灵元素 const ghostCard = sourceCard.cloneNode(true); document.body.appendChild(ghostCard); // 设置幽灵元素的初始位置(和原卡牌重叠) gsap.set(ghostCard, { position: "absolute", top: sourceCard.offsetTop, left: sourceCard.offsetLeft, width: sourceCard.offsetWidth, height: sourceCard.offsetHeight, zIndex: 9999, pointerEvents: "none" // 避免动画过程中干扰点击 }); // 获取卡组列表的目标位置 const deckList = document.getElementById("deck-list"); const targetRect = deckList.getBoundingClientRect(); // 执行动画:移动+缩小+淡出 gsap.to(ghostCard, { x: targetRect.left - sourceCard.offsetLeft, y: targetRect.top - sourceCard.offsetTop, width: 50, // 缩小到卡组卡片的大小 height: 50, opacity: 0, duration: 0.6, ease: "power2.out", onComplete: () => { // 动画结束后移除幽灵元素,更新卡组 ghostCard.remove(); updateDeck(cardName); } }); } // 把之前的数量更新逻辑抽成单独函数 function updateDeck(cardName) { const deckList = document.getElementById("deck-list"); const existingCard = deckList.querySelector(`.card-body[data-card="${cardName}"]`); if (existingCard) { cardQuantity[cardName]++; existingCard.querySelector(".card-count").textContent = `x${cardQuantity[cardName]}`; } else { const template = document.querySelector(`.card-body[data-card="${cardName}"]`); const clone = template.cloneNode(true); cardQuantity[cardName] = 1; deckList.appendChild(clone); } }
总结
你的初始思路是可行的,只要逐步解决对应卡牌匹配、唯一id规范、数量跟踪这几个基础问题,再结合GSAP实现动画,就能完成你想要的卡组 builder 功能啦。建议先把基础功能调试通,再添加动画效果,这样更容易排查问题。
备注:内容来源于stack exchange,提问作者artcank




