简体   繁体   中英

nuxtjs toggle individual items generated by v-for loop

I want to create a simple accordion like structure but somehow I can't manage to toggle individual elements:

<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>

How would I go about toggling indiviual question/answer blocks? Do I need to use refs?

Currently I can toggle all elements ...

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

I could draft up a Q/A component and then do toggle inside of each Component but I believe that is an overkill for this.

UPDATE I am dealing with following data structure:

{
    "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"
                }
                {...}
            ]
        }
    ]
}

This is how to properly mutate a property of an object into an array that you are looping on.

<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://v2.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>

Btw, please do not use v-html as is but pass it through a sanitizer .

Since I did not have an id and done field on the individual question/answer object and I would have needed to loop through several q/a groups, It was easier and more performant to create a sub component in that case to target the individual q/a rows for toggle:

<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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM