在 v-for items 内部切换会影响整个列表,如何让每个切换只影响包含的列表项?

Toggle inside v-for items affects the entire list, how can I make the each toggle affect only the containing list item?

我正在使用 v-for 循环制作项目列表。在循环的每个项目中,都有带有显示描述文本的单击事件方法的按钮。 当我点击按钮时,它应该只在它自己的项目内切换,但它会影响 v-for 列表中的所有元素。

那么,如何制作一个只影响它自己的项目的切换方法?

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

如果要显示说明,您可以在列表中的每个项目上添加 属性:

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

或者,您可以将 li 提取到单独的组件中。

正如@Nora 所说,您可以(并且可能应该)为每个列表项创建一个单独的组件,因此您将拥有一个接受 item 作为道具的组件,然后每个组件都可以拥有自己的组件isActive 标志,使标记保持整洁:

分量:

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

标记

现在您只需将组件放入 v-for:

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

这是 JSFiddle:https://jsfiddle.net/w10qx0dv/

我运行遇到了同样的问题,我是这样解决的。 我获取了一个数组并推送了点击项目的索引,并根据数组中可用的索引,我们现在可以显示或隐藏该元素。

<template>
  <div>
    <div v-for="(item,i) in items">
      <div class="item-text">
        {{ item.text }}
      </div>
      <button @click="toggle(i)">show</button>
      <div v-show="clickedItems.includes(i)" 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.',
  
          }
        ],
        clickedItems:[]
      }
    },
    methods: {
      toggle() {
        if (this.clickedItems.includes(i)) {
          this.clickedItems.splice(this.clickedItems.indexOf(i), 1);
        } else {
          this.clickedItems.push(i);
        }
      }
  },
}
</script>