未捕获的类型错误:无法读取未定义的属性“style”-未定义的值,但我不知道为什么
2020-04-26
472
因此,我尝试在单击卡片时翻转卡片。 我在 addEventListener 之前执行了 console.log(card[i]),它工作正常,但在 addEventListener 之后,console.log 上出现了错误。
我收到的错误是: Uncaught TypeError:无法读取未定义的属性“style”
这些是我的代码
var card = document.querySelectorAll('.card');
var cardInner = document.querySelectorAll('.card-inner');
var cardBack = document.querySelectorAll('.card-back');
for (var i=0; i < card.length; i++) {
console.log(card[i]); // works fine
// when a card is clicked
card[i].addEventListener('click', function(){
// flip THAT card
console.log(card[i]); // undefined value
card[i].style.perspective = "500px";
cardInner[i].style.transform = "rotateY(180deg)";
cardInner[i].style.transition = "all 0.5s";
cardBack[i].style.transform = "rotateY(180deg)";
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memory Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="box">
<div class="card">
<div class="card-inner">
<div class="card-front"></div>
<div class="card-back"></div>
</div>
</div>
<div class="card">
<div class="card-inner">
<div class="card-front"></div>
<div class="card-back"></div>
</div>
</div>
</section>
<script src="app.js"></script>
</body>
</html>
2个回答
此处的问题是您正在创建一个 闭包 ,并且您正在关闭错误的变量。
您创建的每个内部函数都将对局部变量
i
进行“关闭”。这意味着循环结束后,此局部变量将保持活动状态,并且内部函数将能够访问它。但是,请务必注意,内部函数可以访问变量
i
,而不是函数创建时
i
的值。点击事件监听器直到循环结束后才会触发,但一旦循环结束,
i
的值为
card.length
,当然
card[i]
将未定义,因为
i
指向
card
数组末尾的一个元素。
您需要做的是分别“关闭”
i
的每个值。实现此目的的一种方法是创建另一个函数并将
i
的值传递给此函数:
function addEventListenerToCard(index) {
card.addEventListener('click', function(){
// flip THAT card
console.log(card[index]);
card.style.perspective = "500px";
cardInner[index].style.transform = "rotateY(180deg)";
cardInner[index].style.transition = "all 0.5s";
cardBack[index].style.transform = "rotateY(180deg)";
});
}
for (var i=0; i < card.length; i++) {
console.log(card[i]); // works fine
// when a card is clicked
addEventListenerToCard(i);
}
在这种情况下,每次调用
addEventListenerToCard
都会为参数
index
创建一个新范围,并且此参数不会改变,因此每个事件侦听器都会跟踪与其关联的卡。
您也可以尝试使用
Array.forEach
代替循环:
card.forEach(function (cardElement, index) {
console.log(card[index]); // can also write "console.log(cardElement);" here
// when a card is clicked
card[index].addEventListener('click', function(){
// flip THAT card
console.log(card[index]); // should no longer be an undefined value
card[index].style.perspective = "500px";
cardInner[index].style.transform = "rotateY(180deg)";
cardInner[index].style.transition = "all 0.5s";
cardBack[index].style.transform = "rotateY(180deg)";
});
});
Luke Woodward
2020-04-26
Luke 完美地回答了另一个解决方案,即在
addEventListener
中使用
event.target
var card = document.querySelectorAll('.card');
for (var i=0; i < card.length; i++) {
// console.log(card[i]); // works fine
// when a card is clicked
card[i].addEventListener('click', function(event){
var elem=event.currentTarget;
var cardInner = elem.querySelector('.card-inner');
var cardBack = elem.querySelector('.card-back');
// flip THAT card
elem.style.perspective = "500px";
cardInner.style.transform = "rotateY(180deg)";
cardInner.style.transition = "all 0.5s";
cardBack.style.transform = "rotateY(180deg)";
});
}
.card{
width:100px;
height:100px;
background-color:red;
margin:5px;
}
.card-inner{
width:90px;
height:90px;
background-color:yellow;
}
.card-front{
margin:5px;
width:50%;
height:50%;
background-color:green;
}
.card-back{
margin:5px;
width:50%;
height:50%;
background-color:orange;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memory Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="box">
<div class="card">
<div class="card-inner">
<div class="card-front"></div>
<div class="card-back"></div>
</div>
</div>
<div class="card">
<div class="card-inner">
<div class="card-front"></div>
<div class="card-back"></div>
</div>
</div>
</section>
</body>
</html>
希望这会有所帮助。
Simone Monaco
2020-04-26