0
点赞
收藏
分享

微信扫一扫

vue列表展开收起

以下是一个基于 Vue 的实现方案,通过为每个列表项单独维护展开状态,确保列表项之间互不影响。核心思路是为每个列表项绑定独立的 isExpanded 状态,并通过箭头图标切换状态和内容显示。

完整代码示例

组件模板(ListComponent.vue)

vue

<template>
  <div class="list-container">
    <div
      v-for="(item, index) in list"
      :key="index"
      class="list-item"
    >
      <!-- 标题行(带箭头) -->
      <div class="title-row" @click="toggleExpand(index)">
        <h3>{{ item.title }}</h3>
        <span class="arrow">
          <!-- 箭头图标:根据展开状态切换方向 -->
          <svg
            xmlns="http://www.w3.org/2000/svg"
            :style="{ transform: isExpanded[index]? 'rotate(180deg)' : 'rotate(0deg)' }"
            width="16"
            height="16"
          >
            <path d="M8 12L3 7 8 2 13 7 8 12Z"/>
          </svg>
        </span>
      </div>

      <!-- 展开内容 -->
      <div class="content" v-show="isExpanded[index]">
        <p>{{ item.content }}</p>
        <!-- 其他详情内容 -->
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';

// 模拟列表数据(包含标题和内容)
const list = ref([
  {
    title: '列表项1',
    content: '这是列表项1的详细内容,点击箭头展开或收起...'
  },
  {
    title: '列表项2',
    content: '这是列表项2的详细内容,点击箭头展开或收起...'
  },
  {
    title: '列表项3',
    content: '这是列表项3的详细内容,点击箭头展开或收起...'
  }
]);

// 为每个列表项维护独立的展开状态(默认关闭)
const isExpanded = ref(new Array(list.value.length).fill(false));

// 切换展开状态的方法
const toggleExpand = (index) => {
  isExpanded.value[index] = !isExpanded.value[index];
};
</script>

<style scoped>
.list-container {
  max-width: 600px;
  margin: 0 auto;
}

.list-item {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  margin-bottom: 16px;
  overflow: hidden;
}

.title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.title-row:hover {
  background-color: #f3f4f6;
}

.arrow {
  font-size: 1.2em;
  transition: transform 0.3s ease;
}

.content {
  padding: 16px;
  background-color: #fff;
  line-height: 1.6;
}
</style>

关键实现步骤

  1. 独立状态管理
  • 使用 isExpanded 数组为每个列表项存储独立的展开状态(true 为展开,false 为收起)。
  • 数组长度与列表数据长度一致,通过索引 index 关联列表项和状态。
  1. 点击事件处理
  • 在标题行绑定 @click="toggleExpand(index)",点击时切换对应索引的 isExpanded 状态。
  • 通过 v-show="isExpanded[index]" 控制详情内容的显示 / 隐藏。
  1. 箭头动画
  • 使用 SVG 箭头图标,通过 transform: rotate() 根据展开状态旋转箭头方向(展开时旋转 180°)。
  • 添加过渡动画 transition: transform 0.3s ease 使切换更平滑。
  1. 样式隔离
  • 使用 scoped 样式确保当前组件的 CSS 不影响其他组件。
  • 通过 overflow: hidden 和 border-radius 实现折叠效果的视觉完整性。

效果说明

  • 点击箭头:单个列表项展开 / 收起,其他列表项状态不受影响。
  • 动画效果:箭头旋转和内容显示 / 隐藏带有过渡动画,提升用户体验。
  • 响应式布局:列表容器宽度可通过 max-width 调整,适应不同屏幕尺寸。

扩展说明

  • 数据驱动:若列表数据动态更新(如异步加载),需在数据更新后重新初始化 isExpanded 数组:

javascript

watch(list, (newVal) => {
  isExpanded.value = new Array(newVal.length).fill(false);
}, { deep: true });

  • 自定义图标:可替换 SVG 图标为 Vant 组件库的 ArrowUp/ArrowDown 图标,或使用字体图标库(如 Font Awesome)。
  • 性能优化:若列表项过多,可使用 vue-virtual-scroller 实现虚拟列表,提升渲染性能。

该方案通过状态隔离和数据索引关联,确保每个列表项的展开行为独立,适用于各类需要折叠详情的列表场景。

举报

相关推荐

0 条评论