vue js类绑定在重复元素上

Posted

技术标签:

【中文标题】vue js类绑定在重复元素上【英文标题】:vue js class binding on repetitious element 【发布时间】:2020-11-07 06:43:45 【问题描述】:

我想创建一个简单的游戏帮助孩子阅读,其实是一种语言学习方法,叫做“静音模式”,反正这是jsfiddle链接

https://jsfiddle.net/raminSafari/b7zhc98q/19/

例如,如果我希望学生首先阅读“笔”,我指向 p(1),然后指向 e(2),最后指向 n(3),代码适用于具有唯一字母的单词,但是当单词类似于“爸爸”,它没有按我想要的方式工作,我希望它显示 d(1)(3), a(2)

这是完整的简化代码(我知道它不可靠)

<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>&nbsp;<strong style="color: red; font-size: 10px;"> num1 </strong>&nbsp;
            </template>
             <template v-else-if = "alphabet == word.second ">
                   <span :class=" 'active': secondActive, alphabet">  alphabet  </span>&nbsp;<strong style="color: red; font-size: 10px;"> num2 </strong>&nbsp;
            </template>
             <template v-else-if = "alphabet == word.third ">
                   <span :class=" 'active': thirdActive, alphabet">  alphabet  </span>&nbsp;<strong style="color: red; font-size: 10px;"> num3 </strong>&nbsp;
            </template>
           
             <template v-else-if = "alphabet == word.forth ">
                   <span :class=" 'active': forthActive, alphabet">  alphabet  </span>&nbsp;<strong style="color: red; font-size: 10px;"> num4 </strong>&nbsp;
            </template>
             <template v-else-if = "alphabet == word.fifth ">
                   <span :class=" 'active': forthActive, alphabet">  alphabet  </span>&nbsp;<strong style="color: red; font-size: 10px;"> num5 </strong>&nbsp;
            </template>
            <template v-else>
                <span class="alphabet">  alphabet  </span>&nbsp;
            </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>

谢谢

【问题讨论】:

【参考方案1】:

您可以将输入的字母存储在一个数组中,这样您就可以获得输入的字母的索引并显示它们。我建议您像这样构建您的代码。这是重构代码的小提琴https://jsfiddle.net/tk41d0wo/

<div id="app">
  <div>
    Current word is <span style="color: red;"> words[currentIndex] </span>
  </div>
  <div>
     <button 
       v-for="letter in letters" 
       :key="letter" 
       @click="inputLetter(letter)"
       :style=" color: (inputs.includes(letter)) ? 'red': 'initial' "
     >
        letter  <small>( getAllLetterPositions(letter).join(', ') )</small>
     </button>
  </div>
  <button @click="resetInputs">
    Reset
  </button>
</div>

在你的组件中...

new Vue(
  el: "#app",
  data: 
    currentIndex: 0,
    words: ['made', 'sad', 'dad'],
    letters: ['p', 'e', 'm', 'n', 'd', 'a', 's'],
    inputs: [],
  ,
  methods: 
    inputLetter(letter) 
      this.inputs.push(letter);
        if(this.inputs.join('') == this.words[this.currentIndex]) 
        this.currentIndex++;
        this.resetInputs();
      
    ,
    getAllLetterPositions(letter) 
        return this.inputs.reduce((positions, current, index) => 
        if(current == letter) 
            return positions.concat(index + 1);
        
        return positions;
      , []).sort(function(a, b)return a-b)
    ,
    resetInputs() 
        this.inputs = [];
    
  
)

【讨论】:

感谢@rjcarf,但这不是我想要的,我说代码适用于具有唯一字母的单词,程序显示数字例如 m(1)、a(2) 和 n(3)一年级的学生想出了它的“人”,但是你给了我一个想法来创造另一个新的简单的游戏,谢谢 很高兴你喜欢它@RaminSafari。我的意思是重构你的代码也使它更短和更简单,但无论如何,愉快的编码。【参考方案2】:

答案不仅仅是复制粘贴代码,而且有点长。如果您不想阅读,可以直接跳到结论。

我阅读了 jsfiddle,这里有一些解决您面临的问题的建议:

1。将数字视为字符串,而不是数字

之后你就会知道d(1)(3)的问题不是显示2个数字,确实是如何追加字符串“1”和“3” 并显示它。

2。分而治之

把你的整个任务分成三个部分:

    创建函数来控制应突出显示哪些字母并显示相应的顺序。 创建一个组件,仅用于显示字母表和序列,例如d(1)(3)。 定义函数以触发渲染过程并重置应用状态。

App.vue

这是App.vue中的数据的样子

data: function() 
    return 
        word: "dad",
        alphabets: ["p", "e", "m", "n", "d", "a", "s"],
        hits: ["", "", "", "", "", "", ""],
        handlers: [],
        delay: 2000,
    
,

this.hits 将存储命中的相应序列。例如,对于 dad,点击量最终会变为:["", "", "", "", "13", "2", ""]

这些是你在App.vue中应该有的功能

循环每个字符。在this.word,并做相应的渲染
renderAnswer: 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 数组,这将触发每个字母的相应渲染
updateHits: 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

把你的大函数分成几个小函数,让它们各自做1件事情。

注意:在这里,您将看到renderAnswer() 调用doSetTimeout()doSetTimeout() 调用updateHits()。为了正确获取数据和函数,我们需要定义var self = this并将self传递给每个函数调用。

字母表的子组件

在App.vue的模板中,需要定义一个&lt;alphabet&gt;子组件。该组件仅负责渲染特定字母表以及与该字母表相关的序列。

<alphabet 
    v-for="(char, index) in alphabets" 
    v-bind:key="char" 
    :alphabet="char" 
    v-bind:hits="hits[index]"
/>

您需要将字母表和相应的命中值传递给子组件才能正确渲染组件。这个子组件的代码应该是直截了当的,所以我将在这里跳过。执行此部分时,您可能需要知道如何从official documentaion 传递和使用props

运行应用程序

当你设置好所有函数和子组件后,你应该可以在触发renderAnswer()时渲染dad的case。

重置状态

您可能需要为每个新词重置应用状态。因此,您还应该定义一个reset() 函数将this.word 更新为一个新单词,并将this.hits 中的每个项目重置为空字符串。

如果您需要上述步骤的更多详细信息,请阅读this gist。

结论

当您在编码方面遇到一些问题时,您可以尝试重新解决您遇到的问题。 提出正确的问题将引导您使用更好的方法解决这些问题。

另一方面,将问题分解为更小的问题并逐个解决。在这种情况下,尝试将大函数拆分为一些更小更简单的函数。并且,尝试创建一个子组件来完成渲染部分,同时将所有逻辑留给它的父组件。

希望你能解决你遇到的问题,帮助更多的孩子:)

【讨论】:

以上是关于vue js类绑定在重复元素上的主要内容,如果未能解决你的问题,请参考以下文章

在Vue中用一个条件绑定多个类[重复]

防止 Vue.js 在慢速客户端上显示括号[重复]

vue.js怎样解决按钮多次点击重复提交

Vue项目按钮重复提交

Vue.js:在导入相同的 css 文件时定义了重复的 CSS 类(CSS 组件)

js和jQuery中的事件绑定与普通事件