Toggle inside v-for items affects the entire list,

2020-02-29 07:07发布

问题:

I'm making a list of items with v-for loop. Inside each item of the loop there is button with click event method that showing description text. When i click on the button, it should toggle only inside it's own item, but it affecting all elements in v-for list.

So, how to make a toggle method that will affect only it's own item?

<template>
  <div>

    <div v-for="item in items" :class="{ activeclass: isActive }">

      <div class="item-text">
        {{item.text}}
      </div>
      <button @click="toggle()">show</button>

      <div v-show="isActive" class="item-desc">
        {{item.desc}}
      </div>

    </div>


  </div>
</template>

<script>
  export default {

    data () {

      return {

        items: [
          {
            text: 'Foo',
            desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
          },
          {
            text: 'Bar',
            desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',

          }
        ],

        isActive: false
      }
    },

    methods: {

      toggle: function () {
        this.isActive = !this.isActive;
      }

    },


  }
</script>

回答1:

As @Nora said you can (and probably should) create a separate component for each list item, so you would have a component that accepts an item as a prop, then each component can have it's own isActive flag, which keeps the markup nice and clean:

Component:

Vue.component('toggle-list-item', {
  template: '#list-item',
  props: ['item'],
  methods: {
    toggle() {
      this.isActive = !this.isActive;
    }
  },
  data() {
    return {
      isActive: false
    }
  },
})

Markup

Now you can simply place the component inside your v-for:

<div id="app">
  <div v-for="item in items">
    <toggle-list-item :item="item"></toggle-list-item>
  </div>
</div>

Here's the JSFiddle: https://jsfiddle.net/w10qx0dv/



回答2:

You can add a property on each item in your list if description should be shown:

<template>
  <ul>
    <li v-for="item in items" :class="{ activeclass: item.isActive }">
      <div class="item-text">
        {{ item.text }}
      </div>
      <button @click="toggle(item)">show</button>
      <div v-show="item.isActive" class="item-desc">
        {{ item.desc }}
      </div>
    </li>
  </ul>
</template>

<script>
  export default {
    data () {
      return {
        items: [
          {
            isActive: false,
            text: 'Foo',
            desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
          },
          {
            isActive: false,
            text: 'Bar',
            desc: 'The Array.from() method creates a new Array instance from an array-like or iterable object.',
          }
        ],
      }
    },
    methods: {
      toggle: function (item) {
        item.isActive = !item.isActive;
      }
    },
  }
</script>

Alternatively, you can extract the li into a separate component.