0
点赞
收藏
分享

微信扫一扫

vue实现过渡效果

方法一:使用 Vue 的 <transition> 组件

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

      <!-- 使用 transition 组件包裹内容区域 -->
      <transition name="slide">
        <div class="content" v-if="isExpanded[index]">
          <p>{{ item.content }}</p>
        </div>
      </transition>
    </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;
  padding: 16px;
  cursor: pointer;
  transition: background-color 0.2s;
}

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

.arrow {
  transition: transform 0.3s ease;
}

/* 内容容器样式 */
.content {
  padding: 16px;
  background-color: #fff;
  line-height: 1.6;
}

/* 定义过渡动画 */
.slide-enter-active,
.slide-leave-active {
  transition: all 0.3s ease;
}

.slide-enter-from,
.slide-leave-to {
  opacity: 0;
  transform: translateY(-10px);
}
</style>

方法二:直接通过 CSS 实现过渡

这种方法更简单,不需要额外的组件。

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]" :class="{ expanded: 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;
  padding: 16px;
  cursor: pointer;
  transition: background-color 0.2s;
}

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

.arrow {
  transition: transform 0.3s ease;
}

/* 内容容器样式 */
.content {
  max-height: 0;
  padding: 0 16px;
  opacity: 0;
  overflow: hidden;
  transition: all 0.3s ease;
}

/* 展开状态样式 */
.content.expanded {
  max-height: 500px;
  padding: 16px;
  opacity: 1;
}
</style>

关键改进点

  1. 使用 v-if 替代 v-show:配合 <transition> 组件,在元素插入 / 移除时触发过渡
  2. 添加过渡 CSS 类:定义进入 / 离开的动画效果
  3. 动态控制内容高度:通过 max-height 和 opacity 实现平滑过渡
  4. 添加 transform 动画:使内容在展开 / 收起时有轻微的位移效果,增强视觉体验

效果说明

  • 展开时:内容从上方平滑滑入,同时渐显
  • 收起时:内容平滑滑出并渐隐
  • 箭头图标也会平滑旋转,与内容动画保持一致
举报

相关推荐

0 条评论