开发者问题收集

未捕获的类型错误:无法读取未定义的属性“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