You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js实现列表每行3个展示、点击选中编辑功能的问题排查

问题根因

你将原始一维items数组切割为按行分组的二维rowArray后,内层循环使用的i是单一行内的局部索引,取值范围固定为0、1、2,所有行的索引都会重复:

  1. 判断激活状态时activeIndex === i会匹配所有行相同位置的元素
  2. 用这个局部索引直接取原始一维items数组,永远只能取到前3个第一行的元素,自然只能编辑第一行内容

修复方案

计算每个条目对应的原始数组全局索引,用全局索引做激活判断和取值:

  1. 点击条目的时候传递 行索引*每行条目数 + 行内索引 作为全局索引
  2. 激活状态判断、编辑取值都用这个全局索引即可

修改后的核心代码

1. 模板部分(item-list-template)
<script type="text/x-template" id="item-list-template">
  <div>
    <input type="text" placeholder="Edit selected items" :value="activeItemValue" @input="setActiveItemValue" />
    <div class="items-col">
      <ul class="items-list" v-for="(row, rowIndex) in rowArray" :key="rowIndex">
        <!-- 计算全局索引:rowIndex * 3 + i,传递给点击事件、用于激活判断 -->
        <item 
          v-for="(item, i) in row" 
          :key="`${rowIndex}-${i}`" 
          :title="item.title" 
          :isActive="activeIndex === (rowIndex * 3 + i)" 
          @click.native="onItemClick(rowIndex * 3 + i)" 
        />
      </ul>
    </div>
  </div>
</script>
2. 逻辑部分无需修改,原有的onItemClick、setActiveItemValue都可以正常复用,因为现在activeIndex存储的已经是原始items数组的全局索引。

如果后续需要调整每行展示的条目数,可以把固定的3抽为公共变量,比如在data里定义itemsPerRow: 3,模板里替换为rowIndex * itemsPerRow + i即可,不用修改多处代码。

完整可运行代码

Vue.component('item-list', {
  template: '#item-list-template',
  data() {
    return {
      items: [
          {title: 'item 1'},
          {title: 'item 2'},
          {title: 'item 3'},
          {title: 'item 4'},
          {title: 'item 5'},
          {title: 'item 6'}
      ],
      activeIndex: -1,
      rowArray: [],
      itemsPerRow: 3 // 抽成变量方便后续修改
    }
  },
  mounted(){
      this.fakeFetchData();
  },
  methods: {
    fakeFetchData(){
        var cloned = this.items.slice();
        while (cloned.length > 0) {
            let chunk = cloned.splice(0,this.itemsPerRow);
            this.rowArray.push(chunk);
        }  
    },
    onItemClick(index) {
      this.activeIndex = this.activeIndex === index ? -1 : index;
    },
    setActiveItemValue(event) {
      const foundItem = this.items[this.activeIndex];
      if (!foundItem) return;
      
      return this.items[this.activeIndex].title = event.currentTarget.value;
    }
  },
  computed: {
    activeItemValue() {
      return this.items[this.activeIndex]?.title ?? '';
    }
  }
});

Vue.component('item', {
  template: '#item-template',
  props: {
    isActive: Boolean,
    title: String
  }
});

new Vue({
  el: '#app'
});
li.active {
  background-color: yellow;
}
.items-list {
    display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <item-list></item-list>
</div>

<script type="text/x-template" id="item-list-template">
  <div>
    <input type="text" placeholder="Edit selected items" :value="activeItemValue" @input="setActiveItemValue" />
    <div class="items-col">
      <ul class="items-list" v-for="(row, rowIndex) in rowArray" :key="rowIndex">
        <item 
          v-for="(item, i) in row" 
          :key="`${rowIndex}-${i}`" 
          :title="item.title" 
          :isActive="activeIndex === (rowIndex * itemsPerRow + i)" 
          @click.native="onItemClick(rowIndex * itemsPerRow + i)" 
        />
      </ul>
    </div>
  </div>
</script>

<script type="text/x-template" id="item-template">
  <li class="item" :class="{ active: isActive }">{{ title }}</li>
</script>

内容的提问来源于stack exchange,提问作者Ioann Sulyma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 08:54:04