I wanna create a simple game helps kids to read, in fact it is a language learning approach named 'silent mode', anyway this is the jsfiddle link
https://jsfiddle.net/raminSafari/b7zhc98q/19/
for example if I want a student to read 'pen' first I point to p(1) then e(2) and finally n(3), the code works fine with words which have unique letters, but when the word is something like 'dad' it is not working the way i want, i want it to show d(1)(3), a(2)
here is the complete simplified code(i know it's not robust)
<template>
<div class = "container pt-5 mt-5">
<h1 class="text-center pb-5"><span style="color: red;"> {{ answer }} </span> just to clarify</h1> <!-- just to clarify -->
<div class="text-center">
<template id="keyboard" v-for="alphabet in alphabets" >
<template v-if = "alphabet == word.first ">
<span :class="{ 'active': firstActive, alphabet}"> {{ alphabet }} </span> <strong style="color: red; font-size: 10px;">{{ num1 }}</strong>
</template>
<template v-else-if = "alphabet == word.second ">
<span :class="{ 'active': secondActive, alphabet}"> {{ alphabet }} </span> <strong style="color: red; font-size: 10px;">{{ num2 }}</strong>
</template>
<template v-else-if = "alphabet == word.third ">
<span :class="{ 'active': thirdActive, alphabet}"> {{ alphabet }} </span> <strong style="color: red; font-size: 10px;">{{ num3 }}</strong>
</template>
<template v-else-if = "alphabet == word.forth ">
<span :class="{ 'active': forthActive, alphabet}"> {{ alphabet }} </span> <strong style="color: red; font-size: 10px;">{{ num4 }}</strong>
</template>
<template v-else-if = "alphabet == word.fifth ">
<span :class="{ 'active': forthActive, alphabet}"> {{ alphabet }} </span> <strong style="color: red; font-size: 10px;">{{ num5 }}</strong>
</template>
<template v-else>
<span class="alphabet"> {{ alphabet }} </span>
</template>
</template>
<div><button class = "btn btn-info mt-3" @click = "again">again</button></div>
</div>
</div>
</template>
<script>
export default {
data(){
return{
alphabets: ["p", "e", "m", "n", "d", "a", "s"],
firstActive: false,
secondActive: false,
thirdActive: false,
forthActive: false,
fifthActive: false,
index: 0,
words:[
{
first: 'p',
second: 'e',
third: 'n',
forth: '',
fifth: '',
answer : 'pen'
},
{
first: 'm',
second: 'a',
third: 'd',
forth: 'e',
fifth: '',
answer : 'made'
},
{
first: 'd',
second: 'a',
third: 'd',
forth: '',
fifth: '',
answer : 'dad'
},
],
word: [],
answer: '',
myVar1: null,
myVar2: null,
myVar3: null,
myVar4: null,
myVar5: null,
num1: '',
num2: '',
num3: '',
num4: '',
num5: ''
}
},
methods: {
shuffle(a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
},
getWord(){
this.word = this.words[this.index];
this.answer = this.word.answer;
},
again(){
clearTimeout(this.myVar1);
clearTimeout(this.myVar2);
clearTimeout(this.myVar3);
clearTimeout(this.myVar4);
clearTimeout(this.myVar5);
this.firstActive = false;
this.secondActive = false;
this.thirdActive = false;
this.forthActive = false;
this.fifthActive = false;
this.num1 = '';
this.num2 = '';
this.num3 = '';
this.num4 = '';
this.num5 = '';
if(this.index == this.words.length){
this.index = 0;
}else{
this.index++;
}
this.getWord();
this.showBorder();
},
showBorder(){
this.myVar1 = setTimeout(() => {
this.firstActive = true;
this.num1 = 1;
}, 2000);
this.myVar2 = setTimeout(() => {
this.secondActive = true;
this.num2 = 2;
}, 4000);
this.myVar3 = setTimeout(() => {
this.thirdActive = true;
this.num3 = 3;
}, 6000);
this.myVar4 = setTimeout(() => {
this.forthActive = true;
this.num4 = 4;
}, 8000);
this.myVar5 = setTimeout(() => {
this.fifthActive = true;
this.num5 = 5;
}, 10000);
}
},
created(){
this.words = this.shuffle(this.words);
this.getWord();
this.showBorder();
}
}
</script>
<style>
span.alphabet{
display: inline-block;
width: 70px;
height: 70px;
font-size: 30px;
font-weight: 600;
}
.active{
border: 2px solid red;
border-radius: 50%;
}
</style>
thank you
The answer is not just a copy-and-paste code and it is a bit long. If you don't want to read that you may just skip to the conclusion.
I read the jsfiddle and here are some suggestions to solve the problem you are facing:
After that, you will know that the d(1)(3) issue is not showing 2 numbers, it's indeed how to append the string "1" and "3" and display it.
Divide your whole task into 3 parts:
This is what the data looks like in App.vue
data: function() {
return {
word: "dad",
alphabets: ["p", "e", "m", "n", "d", "a", "s"],
hits: ["", "", "", "", "", "", ""],
handlers: [],
delay: 2000,
}
},
this.hits
will store the corresponding sequences of the hit. For example, for the case of dad, the hits will eventually become: ["", "", "", "", "13", "2", ""]
.
These are the functions you should have in App.vue
this.word
, and do corresponding renderingrenderAnswer: function() {
var self = this;
for (var i = 0; i < this.word.length; i++) {
self.doSetTimeout(i, self);
}
}
doSetTimeout: function (i, self) {
self.handlers.push(setTimeout(function () {
self.updateHits(i, self)
}, self.delay * i));
}
hits
array, and this will trigger corresponding rendering on each alphabetupdateHits: function(i, self) {
let char = self.word[i];
let index = self.alphabets.indexOf(char);
console.debug(char, index)
self.hits[index] += (i + 1);
self.hits = self.hits.filter(x => true); // force refresh list for binding
}
Divide your big function into some smaller functions and let each of them just doing 1 thing.
Note: Here, you will see renderAnswer()
calls doSetTimeout()
and doSetTimeout()
calls updateHits()
. In order to get the data and functions correctly, we need to define var self = this
and pass self
to each function call.
In the template of App.vue, you need to define a <alphabet>
sub-component. This component is solely responsible for render a particular alphabet and the sequence related to that alphabet.
<alphabet
v-for="(char, index) in alphabets"
v-bind:key="char"
:alphabet="char"
v-bind:hits="hits[index]"
/>
You need to pass the alphabet and the corresponding hit value to the sub-component in order to render the component properly. The code of this sub-component should be straight-forward so I will skip it here. You may need to know how to pass and use props
from the official documentaion when doing this part.
When you set up all the functions and the sub-component, you should be able to render dad
's case when you trigger renderAnswer()
.
You may need to reset the app status for each new word. Therefore, you should also define a reset()
function to update this.word
into a new word, and reset each item in this.hits
as empty string.
Read this gist if you need more details of the above steps.
When you are facing some problem on coding, you can try to re-phasing the problem you met. Asking the right questions will lead you to solve them using a better approach.
On the other hand, break down the problem into smaller problems and tackle them one by one. In this case, try to split the big function into some smaller and simpler functions. And, try to create a sub-component to do the rendering part while leave all the logic to its parent.
Hope you can solve the problem you met and help more kids :)