nuxtjs 切换由 v-for 循环生成的单个项目

Posted

技术标签:

【中文标题】nuxtjs 切换由 v-for 循环生成的单个项目【英文标题】:nuxtjs toggle individual items generated by v-for loop 【发布时间】:2021-11-09 15:59:10 【问题描述】:

我想创建一个简单的手风琴式结构,但不知何故我无法切换单个元素:

<div v-for="qa, j in group.questions_answers" :key="j">
  <div class="question" @click="toggle()" > <!-- use index here? -->
    <span v-if="itemOpen" class="font-iconmoon icon-accordion-up"><span/>
    <span v-else class="font-iconmoon icon-accordion-down"><span/>
    <span class="q-text" v-html="qa.question"><span/>
  </div>
  <div v-if="itemOpen" class="answer" v-html="qa.answer"></div>
</div>

我将如何切换各个问题/答案块?我需要使用 refs 吗?

目前我可以切换所有元素...

export default 
  data() 
    return 
      itemOpen: true
    
  ,
  methods: 
    toggle()  // index
      this.itemOpen = !this.itemOpen
    
  

我可以起草一个 Q/A 组件,然后在每个组件内部进行切换,但我认为这样做有点过头了。

更新我正在处理以下数据结构:


    "intro_text": "intro text",
    "questions_groups": [
        
            "group_heading": "heading",
            "questions_answers": [
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                ...
            ]
        ,
        
            "group_heading": "heading 1",
            "questions_answers": [
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                ...
        ,
        
            "group_heading": "heading 2",
            "questions_answers": [
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                ,
                
                    "question": "Question",
                    "answer": "Answer"
                
                ...
            ]
        
    ]

【问题讨论】:

我想我可以使用索引做类似的事情:***.com/questions/60902395/… 【参考方案1】:

这是如何正确地将对象的属性更改为您正在循环的数组。

<template>
  <!-- eslint-disable vue/no-v-html -->
  <article>
    <div
      v-for="todo in todoList"
      :key="todo.id"
      class="question"
      @click="toggleMyTodo(todo)"
    >
      <span
        v-if="isTodoDone(todo)"
        class="font-iconmoon icon-accordion-up"
      ></span>
      <span v-else class="font-iconmoon icon-accordion-down"></span>
      <span class="q-text" v-html="todo.question"></span>
      <div v-if="isTodoDone(todo)" class="answer" v-html="todo.answer"></div>
    </div>
  </article>
</template>

<script>
export default 
  data() 
    return 
      todoList: [
        
          id: 1,
          task: 'Cook',
          done: false,
          question: 'duh?',
          answer: 'ahh okay!',
        ,
        
          id: 2,
          task: 'Hover',
          done: false,
          question: 'duh?',
          answer: 'ahh okay!',
        ,
        
          id: 3,
          task: 'Washing machine',
          done: false,
          question: 'duh?',
          answer: 'ahh okay!',
        ,
      ],
    
  ,
  methods: 
    toggleMyTodo( id ) 
      const currentTodoIndexToToggle = this.todoList.findIndex(
        (todo) => todo.id === id
      )
      // $set is used because of this https://vuejs.org/v2/guide/reactivity.html#For-Arrays
      this.$set(this.todoList, currentTodoIndexToToggle, 
        ...this.todoList[currentTodoIndexToToggle],
        done: !this.todoList[currentTodoIndexToToggle].done,
      )
    ,
    isTodoDone( id ) 
      // I'm using `?.` just to be sure https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Operators/Optional_chaining
      return this.todoList.find((todo) => todo.id === id)?.done
    ,
  ,

</script>

顺便说一句,请按原样do not use v-html,但请通过a sanitizer。

【讨论】:

我没有id,也没有每个元素的done 标志。对于id,我想我可以在这里使用index。我使用 v-html 没有经过清理,因为我知道来源并且它不是用户输入。 html 来自旧版 cms ... @mahatmanich 不,不要在这里使用索引,它完全适得其反,并且与它应该做的相反。此外,如果您没有 ID 和状态检查,请使用 .map 在您的阵列上循环并添加它们! 我知道,我很高兴两者兼有 :-) 我会一如既往的 ;-) 你在很多 vue/nuxt 问题上帮助了我,我非常感谢!我会尝试更多其他方法,然后回到这里。 也感谢 cmets 关于 v-html 和结束标签,感谢!【参考方案2】:

由于我在单个问题/答案对象上没有 iddone 字段,并且我需要遍历多个 q/a 组,因此在这种情况下,将单个 q/a 行作为切换目标:

<template>
  <div>
    <slot-main-heading>$t('faq.h1')</slot-main-heading>
    <div v-html="introText"></div>
    <div v-for="(group, i) in questionsGroups" :key="i">
      <slot-htwo-heading>group.group_heading</slot-htwo-heading>
      <template v-for="(qa, j) in group.questions_answers">
        <cms-accordion-row :qaData="qa" :key="j"/>
      </template>
    </div>
  </div>
</template>

cmsAccordionRow.vue

<template>
<div>
  <div class="question" @click="toggle()">
      <span v-if="itemOpen" class="font-iconmoon icon-accordion-up" ></span>
      <span v-else class="font-iconmoon icon-accordion-down" ></span>
      <span class="q-text" v-html="qaData.question" ></span>
  </div>
  <div v-if="itemOpen" class="answer" v-html="qaData.answer"></div>
</div>
</template>

<script>
export default 
  props: 
    qaData: 
      type: Object,
      required: true
    
  ,
  data() 
    return 
      itemOpen: true
    
  ,
  methods: 
    toggle() 
      this.itemOpen = !this.itemOpen
    
  

</script>

【讨论】:

@kissu 我不得不这样做...... 我不确定这里发生了什么,也不确定您的实际数据的格式。为什么这里不能有一些像样的数据集而需要使用一些挑剔的技巧?没有视觉效果我也无能为力,是的,坚持我猜的可行解决方案。以后您将无法通过细粒度控制访问数据集。 @kissu 我更新了问题中的数据结构。这就是我要与之合作的...... 这是什么意思?它从何而来?为什么不按自己的喜好按摩呢?有时问题不在预期的位置。 对你正在循环的实际事物进行一些跟踪,并将特定状态绑定到元素总是很好的。正如我告诉你的,如果你对你的解决方案没意见,那就保持这样吧!

以上是关于nuxtjs 切换由 v-for 循环生成的单个项目的主要内容,如果未能解决你的问题,请参考以下文章

Vue.JS v-for循环后,想要实现每个单独项实现单独的show的true\false

Vue中的v-for循环,实现div块的循环生成

Vue.js 使用 v-for 单击时切换类

Vuejs - 如何使用 v-for 获取数组中的所有唯一值(删除重复项)

第十节:Vue指令:v-for列表循环

第十节:Vue指令:v-for列表循环