📜 ⬆️ ⬇️

Creating a quiz on Vue.js

Vue.js


I don't understand Angular. I really like React, but I'm still learning its basics. Let's try Vue . I will tell you how I did a micro-quiz.


Initialization


HTML


First create a small HTML skeleton and connect Vue.


<html> <body> <!-- Vue    div- --> <div id="app"> <!--  data.title  Vue   --> <h1>{{ title }}</h1> </div> <!--   Vue --> <script src="https://vuejs.org/js/vue.js"></script> <!--     Vue --> <script> window.onload=function(){ new Vue({ el: '#app', // Vue    div- (  4) data: { title: 'Hello.' }, // title    'Hello.' }); } </script> </body> 

Save it as foo.html and open it in a browser. You should see Hello. , - this means that everything works. We have just learned how to display data using the Mustache syntax: {{title}}


Data


Then create a simple quiz object and add it to the Vue instance data.


 <script> window.onload=function(){ //       . //              . var quiz = { title: ' ', questions: [ { text: " 1", responses: [ {text: ',  .'}, {text: '!', correct: true}, ] }, { text: " 2", responses: [ {text: ' ', correct: true}, {text: ' '}, ] } ] }; new Vue({ el: '#app', data: { quiz: quiz }, //      Vue }); } </script> 

This is our quiz, the next step is to display it using Vue cycles.


HTML data display


Vue provides a declarative loop system by adding the attribute v-for = "item on items" to an HTML element.


 <div id="app"> <!--   --> <h1>{{ quiz.title }}</h1> <!-- :  div    --> <div v-for="question in quiz.questions"> <h2>{{ question.text }}</h2> <!-- :  li  -     --> <ol> <li v-for="response in question.responses"> <label> <input type="radio"> {{response.text}} </label> </li> </ol> </div> </div> 

Vue has an unobtrusive reactive system . If the data object changes, the HTML mapping is updated. Now the quiz is completely ready, it is lively and reactive.



Until now, all questions were displayed on one page. Let's change the quiz so that only one question per page is displayed. To do this, we need to add the “Next” and “Previous” buttons for each question and hide all the questions that are not current.


Vue instance: navigation methods


The application we created must deal with user input: button presses. First add the current question index field and two navigation methods to the Vue instance.


 new Vue({ el: '#app', data: { quiz: quiz, //     questionIndex: 0, }, //       methods: { //     next: function() { this.questionIndex++; }, //     prev: function() { this.questionIndex--; } } }); 

The questionIndex field is incremented with next () and decremented with prev ()


HTML: navigation buttons


Create a button with the directive v-on: click = "next" to call the next () method. Add v-show = "index === questionIndex" to the question container to display only the current question (do not forget to add the index parameter to the v-for directive)


 <div id="app"> <h1>{{ quiz.title }}</h1> <!--        --> <div v-for="(question, index) in quiz.questions"> <!--   ,        --> <div v-show="index === questionIndex"> <h2>{{ question.text }}</h2> <ol> <li v-for="response in question.responses"> <label> <input type="radio"> {{response.text}} </label> </li> </ol> <!--   --> <!-- :  ""       --> <button v-if="questionIndex > 0" v-on:click="prev">  </button> <button v-on:click="next">  </button> </div> </div> </div> 

Now we can move inside the quiz. The last page is empty, on it we must display the results of the quiz.


Quiz result


To display the result of the quiz, we must process the user answers for each question. It was the most difficult step for me.


Processing User Responses


Right now, the quiz radio buttons do not have a Vue link: clicking a radio button has no effect. The v-model directive creates a two-way connection between form input and application state. Replace the previously created radio button.


 <!--      --> <li v-for="response in question.responses"> <label> <!-- -  3   --> <!-- v-bind:value  "value"   "true"    --> <!-- v-bind:name  "name"          --> <!-- v-model    userResponses --> <input type="radio" v-bind:value="response.correct" v-bind:name="index" v-model="userResponses[index]"> {{response.text}} </label> </li> 

The name and value attributes are bound to Vue data. Then initialize userResponses on the Vue instance.


 new Vue({ el: '#app', data: { quiz: quiz, questionIndex: 0, //     "false"    //  : "     n?" "". userResponses: Array(quiz.questions.length).fill(false) }, methods: { // ... } }); 

This was the last step to process user responses: userResponses contains a live array of “true if the answer is correct” . You can move back and forth, select and change responses, and see userResponses updates.


Show account


The final score is the sum of the “true” values ​​in userResponses . Create a method in the Vue application to compute this account.


 new Vue({ // ... methods: { // ... //   "true"  userResponses score: function() { return this.userResponses.filter(function(val) { return val }).length; } } }); 

Then add a summary page of the quiz with the total score.


 <div id="app"> <h1>{{ quiz.title }}</h1> <div v-for="(question, index) in quiz.questions"> <!-- //... --> </div> <!--  ,  ,   --> <div v-show="questionIndex === quiz.questions.length"> <h2>   </h2> <p> : {{ score() }} / {{ quiz.questions.length }} </p> </div> </div> 

That's it, the quiz works. You can try it or download the code .


Afterword


My javascript skills are a bit lame and I just started doing Vue. I wanted to share the feeling of how easy it is to start working with him. Feel free to criticize me.


')

Source: https://habr.com/ru/post/336328/


All Articles