【问题标题】:Javascript personality quiz trouble using 'this' and data-* attributes使用 'this' 和 data-* 属性的 Javascript 个性测验问题
【发布时间】:2016-04-07 15:33:11
【问题描述】:

我正在尝试使用纯 javascript 来创建点击个性测验以进行单项作业。我有一堆 div 布局,以便它们应该出现。每个问题都有一个列表,其中包含 4 个(左右)与不同性格类型相关的答案。我打算保留一组对象来统计每个选定的答案,并在最后提供人格类型的细分。

我目前被困在功能上;

  1. 记录选中的数据并将其添加到answers数组中,
  2. 隐藏当前问题的div和
  3. 显示下一个问题 div

HTML

<div class="question" id="q1"  data-next="q2">
  <h2>Question 1:</h2>
  <p>Which of the following is your favourite movie? </p>
  <ol class="button">
    <li data-score="Ninja">Karate Kid</li>
    <li data-score="Robot">Wall-E</li>
    <li data-score="Pirate">Pirates of the Caribbean</li>
    <li data-score="Zombie">Dawn of the Dead</li>
  </ol>
</div>

<div class="question" id="q2" data-next="q3">
  <h2>Question 2:</h2>
  <p>A building is on fire and you hear a child's screaming for help from the third floor window. Do you: </p>
  <ol class="button">
    <li data-score="Ninja">Mysteriously disappear and re-appear with the children</li>
    <li data-score="Robot">Run in and save the child on the second floor, because i'm made of metal and fire won't hurt me!</li>
    <li data-score="Pirate">Dress up as a pirate and loot the surrounding neighbourhood, including the bank?</li>
    <li data-score="Zombie">Eat all the brains. Nom nom uuuuggghhh.</li>
  </ol>
</div>

JS:

 // Create a listener for clicks on the 'start the quiz' button on the front page. 
    document.getElementById("beginquiz").addEventListener("click", startQuiz);

// When the button is clicked the 'intro' div is hidden and the first question div is displayed
function startQuiz () {
    document.getElementById("intro").style.display = "none";
    document.getElementById("q1").style.display = "block";
}

// Create an array object to store all the quiz answers. Each selected answer should increase the category score by 1. The highest score will be the personality 'type' in the results. 
var answerData = [
    {name: "Ninja" , score: 0},
    {name: "Robot" , score: 0},
    {name: "Pirate" , score: 0},
    {name: "Zombie" , score: 0} ]

// Get all of the .buttons elements
var buttons = document.querySelectorAll(".button");
// Add an onclick event listener to every element with a class of .buttons
for (var i = 0 ; i < buttons.length ; i++) {
    // When an element with .buttons is clicked, run the function called buttonClicked
    buttons[i].onclick = buttonClicked;
    }

// Define what buttonClicked does
function buttonClicked() {
    // Get the current element's data-score value
    var selectedType = this.dataset.score;
    // Increase the selected answer's 'type' by 1
    answerData["selectedType"].score++;
    // Hide the current question div
    this.parentElement.style.display = "none";
    // Work out what the next question div is
    var nextQuestion = this.parentElement.dataset.next;
    // Display the next question element
    document.getElementById(nextQuestion).style.display = "block";
}

摆弄我到目前为止所做的事情https://jsfiddle.net/funkefiddle/e1za0gtr/1/

出于某种原因,我认为 data-score 是一个在可点击答案元素之间建立联系并实际跟踪它的好地方。但是,显然我的代码实际上并没有工作。 Firefox 控制台显示“this.dataset.score is undefined”。

var selectedType = this.dataset.score.value;
answerData["selectedType"].score++;

请停下来。

另外 - 我不知道显示系列中下一个元素的代码是否可以工作,因为我的错误检查还没有做到那么远。我只是写了我的大脑建议可能有用的东西。

编辑:去掉 .value 因为我不知道为什么我一开始就有它。 还更改了最后一行以使 nextQuestion 成为变量而不是字符串。问题现在显示/隐藏在进程中(当我注释掉 answerData 行时。

我想这意味着我被困在我想增加所选答案类型的数组值的行上。

answerData[selectedType].score++ ;

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    需要更正的几点:

    1. 当您将处理程序绑定到 ol 元素时,this 指的是该元素。该元素上不存在 score 数据。相反,您可以使用事件对象的target 来了解实际单击的元素。

    2. 在检索data-score 属性的值时,您应该只引用dataset.score,而不是dataset.score.value

    3. answerData["selectedType"] 有两个问题:它处理answerData 不是作为数组,而是作为对象;而“selectedType”是一个字面量,不会成为同名变量的值。删除引号,并将您的数据结构 answerData 更改为普通对象,而不是数组:

      var answerData = { // one object, with names as keys, scores as values
          "Ninja": 0,
           "Robot": 0,
          "Pirate": 0,
          "Zombie": 0};
      
    4. getElementById 的参数不应以散列开头。您需要像这样传递 id,不带散列。

    5. ...你需要用忍者的东西完成其他问题... ;-)

    这是带有这些更正的代码——我没有完全完成第 5 点:

    // Create a listener for clicks on the 'start the quiz' button on the front page. 
    document.getElementById("beginquiz").addEventListener("click", startQuiz);
    
    // When the button is clicked the 'intro' div is hidden and the first question div is displayed
    function startQuiz () {
        document.getElementById("intro").style.display = "none";
        document.getElementById("q1").style.display = "block";
    }
    
    // Create an array object to store all the quiz answers. Each selected answer should increase the category score by 1. The highest score will be the personality 'type' in the results. 
    var answerData = { // one object, with names as keys, scores as values
        "Ninja": 0,
         "Robot": 0,
        "Pirate": 0,
        "Zombie": 0};
    
    // Get all of the .buttons elements
    var buttons = document.querySelectorAll(".button");
    // Add an onclick event listener to every element with a class of .buttons
    for (var i = 0 ; i < buttons.length ; i++) {
        // When an element with .buttons is clicked, run the function called buttonClicked
        buttons[i].onclick = buttonClicked;
        }
    
    // Define what buttonClicked does
    function buttonClicked(e) {
        var target = e.target; // 1. `this` is parent, need target
        console.log(target);
        // Get the current element's data-score value
        var selectedType = target.dataset.score;   // 2. score is the value
        // Increase the selected answer's 'type' by 1
        console.log(selectedType);
        answerData[selectedType]++;  // 4. after change of structure
        // Hide the current question div
        this.parentElement.style.display = "none";
        // Work out what the next question div is
        var nextQuestion = this.parentElement.dataset.next;
        // Display the next question element
        console.log(nextQuestion);
        document.getElementById(nextQuestion).style.display = "block"; // no hash!
    }
    .question, #result {
        display: none;
        }
    
    .button li {
        border: 1px solid;
        border-radius: 3px;
        background-color: #eee;
        text-align: center;
        line-height: 2em;
        padding: 0.5em;
        margin: 0.5em;
        width: 80%;
        margin: 0 auto;
    }
    
    .button li:hover {
        color: #bfbfbf;
        background-color: #555;
    }
    
    #intro, .question, #result {
        max-width: 600px;
        margin: 0 auto;
    }
    
    #beginquiz {
        border: 1px solid;
        border-radius: 3px;
        background-color: #eee;
        text-align: center;
        line-height: 2em;
        padding: 0.5em;
        margin: 0.5em;
        width: 20em;
        margin: 0 auto;
    }
    #beginquiz:hover {
        color: #bfbfbf;
        background-color: #555;
    }
    <div id="intro">
      <h2>Welcome to Ewan L's Assignment 1 Quiz.</h2>
      <button id="beginquiz">Start the quiz</button>
    </div>
    
    <div class="question" id="q1"  data-next="q2">
      <h2>Question 1:</h2>
      <p>Which of the following is your favourite movie? </p>
      <ol class="button">
        <li data-score="Ninja">Karate Kid</li>
        <li data-score="Robot">Wall-E</li>
        <li data-score="Pirate">Pirates of the Caribbean</li>
        <li data-score="Zombie">Dawn of the Dead</li>
      </ol>
    </div>
    
    <div class="question" id="q2" data-next="q3">
      <h2>Question 2:</h2>
      <p>A building is on fire and you hear a child's screaming for help from the third floor window. Do you: </p>
      <ol class="button">
        <li data-score="Ninja">Mysteriously disappear and re-appear with the children</li>
        <li data-score="Robot">Run in and save the child on the second floor, because i'm made of metal and fire won't hurt me!</li>
        <li data-score="Pirate">Dress up as a pirate and loot the surrounding neighbourhood, including the bank?</li>
        <li data-score="Zombie">Eat all the brains. Nom nom uuuuggghhh.</li>
      </ol>
    </div>
    
    <div class="question" id="q3" data-next="q4">
      <h2>Question 3:</h2>
      <p>Where do you call home?</p>
      <ol class="button">
        <li data-score="Ninja">A magical castle in the English countryside </li>
        <li data-score="Robot">A dark and secret cave in the distant mountains</li>
        <li>A secluded hut in the woods</li>
        <li>34 Tooranimble St, Kanimboolaga NSW</li>
        <li>The sea is my only home. Man the rigging you scurvy sea dog! YARR</li>
      </ol>
    </div>
    
    <div class="question" id="q4" data-next="q5">
      <h2>Question 4:</h2>
      <p>What is your favourite letter?</p>
      <ol class="button">
        <li data-score="Ninja">A</li>
        <li data-score="Robot">B</li>
        <li>C</li>
        <li>Rrrr</li>
      </ol>
    </div>
    <div class="question" id="q5" data-next="q6">
      <h2>Question 5:</h2>
      <p>What is your favourite music?</p>
      <ol class="button">
        <li data-score="Ninja">Rrrr and B</li>
        <li data-score="Robot">Robo-boogie</li>
        <li></li>
        <li></li>
      </ol>
    </div>
    <div class="question" id="q6" data-next="q7">
      <h2>Question 6:</h2>
      <p>If you were a pirate, would you:</p>
      <ol class="button">
        <li data-score="Ninja">Lead a quiet life of solace and penance</li>
        <li data-score="Robot">Loot and plunder</li>
        <li>Wear an eye-patch</li>
        <li>Have one leg</li>
        <li>All of the above, except for number 1. </li>
      </ol>
    </div>
    <div class="question" id="q7" data-next="result">
      <h2>Question 7:</h2>
      <p>Do you like pirates?</p>
      <ol class="button">
        <li data-score="Ninja">Yes</li>
        <li data-score="Robot">No</li>
        <li>I'm just here for the free cookies</li>
        <li>How did i get this far into the quiz? What am i doing with my life??</li>
      </ol>
    </div>
    
    <div id="result">
      <h2>HAHA we fooled you matey. You're a pirate through and through.</h2>
    </div>

    【讨论】:

    • 当我阅读此回复时,我并没有骗你,我的 spotify 播放列表开始播放《银河护卫队》真棒混音第 1 卷中的“Come and get your love”,非常感谢您的回复。在此之前我什至从未听说过事件目标。
    • 不客气。让我知道你想听下一首歌:P
    【解决方案2】:

    answerData 是一个数组。但是你使用它就好像它是一个具有属性的对象。您可以将数组更改为具有属性名称的对象,或者您必须映射 name 属性并获取所选值的索引。

    要么将数组更改为像这样的对象:

    var answerData = {
        "Ninja": { score: 0 },
        "Robot": { score: 0 },
        "Pirate": { score: 0 },
        "Zombie": { score: 0 }
    }
    

    然后从 'selectedType' 字符串快速更改为实际对象:

    answerData[selectedType].score++; // remove quote around selectedType
    

    或者将其保留为数组,但通过首先创建一个映射名称的数组来更新您更新它的方式:

    var answerDataNames = answerData.map(function(obj){
        return obj.name;
    }
    

    您的代码将如下所示:

     // Get the current element's data-score value
    var selectedType = this.dataset.score;
    // Increase the selected answer's 'type' by 1
    var selectedIndex = answerDataNames.indexOf(selectedType);
    answerData[selectedIndex].score++;
    

    【讨论】:

    • 具有属性的对象绝对是我的想法。我将 JS 更新为: function buttonClicked() { var selectedType = this.dataset.score; answerData[selectedType].score++; this.parentElement.style.display = "无"; var nextQuestion = this.parentElement.dataset.next; document.getElementById(nextQuestion).style.display = "block";但是我仍然收到控制台错误“TypeError: answerData[selectedType] is undefined”
    • @Funkyflow selectedType 可能未定义。该解决方案由 trincot 回答。所以你所要做的就是把他那部分的sn-p代码和我的结合起来
    猜你喜欢
    • 1970-01-01
    • 2014-04-10
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 2013-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多