JavaScript 点击卡片时如何正确传参并翻转?
数据小陈
结论
报错发生在点击回调读取 deck[i] 时。循环结束后,i 已等于 deck.length,所以 deck[i] 的值是 undefined。可以用 forEach 给每张卡片绑定回调,并将当前卡片对象传给 Flip。
原代码还有几处属性名不一致:对象保存的是 front、back 和 state,翻转函数读取的却是 cardFront、cardBack 和 cardState。此外,selectedState 没有定义。下面的代码统一使用卡片对象中已有的属性。
修改 JavaScript
用以下代码替换原来的 JavaScript。deckSize 保持为 1,因此循环会创建索引为 0 和 1 的两张卡片:
window.onload = function () {
const deckSize = 1;
const deck = [];
for (let i = 0; i <= deckSize; i++) {
const card = {
name: document.getElementById("card" + i),
inner: document.getElementById("cardInner" + i),
front: document.getElementById("cardFront" + i),
back: document.getElementById("cardBack" + i),
value: i,
state: "faceDown"
};
deck.push(card);
}
deck.forEach((card) => {
card.name.addEventListener("click", () => Flip(card));
});
function Flip(card) {
if (card.state === "faceDown") {
card.front.style.transition = "all 1s";
card.front.style.transform = "rotateY(0deg)";
card.back.style.transition = "all 1s";
card.back.style.transform = "rotateY(180deg)";
card.state = "faceUp";
} else {
card.front.style.transition = "all 1s";
card.front.style.transform = "rotateY(180deg)";
card.back.style.transition = "all 1s";
card.back.style.transform = "rotateY(0deg)";
card.state = "faceDown";
}
}
};
forEach 的回调参数 card 是当前遍历到的卡片。点击监听器通过 () => Flip(card) 捕获这个对象,因此点击卡片时会直接把对应对象传给 Flip,无需再用循环变量查找数组项。
为什么原代码会报错
原来的监听器在循环中创建:
for (i = 0; i < deck.length; i++) {
deck[i].name.addEventListener("click", function() {
Flip(deck[i].value);
});
}
点击事件不会在绑定监听器时立即执行。等循环结束后,i 已经等于 deck.length,回调再访问 deck[i] 就会越过数组末尾。原代码也没有用 let 或 const 声明 i。上面的 forEach 写法让回调使用当前卡片对象,不依赖循环结束后的变量值。
需要留意的属性名
卡片对象定义了 front、back 和 state,翻转逻辑也应使用这些属性。示例中没有定义 selectedState;每张卡片的状态保存在 card.state 中。
原代码中的 deck[deckNum].console.log("Flip Back") 也不正确。console.log 应直接调用,不能通过卡片对象访问。修正后的代码不需要这条调试语句。
备注:内容仅供参考。
