50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | FAQ Collapse(问题解答折叠面板)

发布于:2025-06-12 ⋅ 阅读:(20) ⋅ 点赞:(0)

📅 我们继续 50 个小项目挑战!—— FAQCollapse组件

仓库地址:https://github.com/SunACong/50-vue-projects

项目预览地址:https://50-vue-projects.vercel.app/

在这里插入图片描述


使用 Vue 3 的 Composition API 和 <script setup> 语法结合 TailwindCSS 构建一个带有动画效果的常见问题(FAQ)折叠面板组件。该组件支持点击展开/收起,并为每个问答项添加了优雅的过渡动画。

🎯 组件目标

  • 展示一组常见问题(FAQ)。
  • 每个问题可以独立展开与收起。
  • 使用 TailwindCSS 快速构建美观的 UI 界面。
  • 添加平滑的动画过渡效果提升用户体验。

⚙️ 技术实现点

技术点 描述
Vue 3 Composition API (<script setup>) 使用响应式变量管理组件状态
v-for 循环渲染 动态生成多个 FAQ 条目
v-if 控制内容显示 判断当前条目是否展开
@click 事件绑定 控制展开/收起动作
Transition 组件 添加进入和离开动画
TailwindCSS 布局与样式 快速构建现代 UI

🧱 组件实现

模板结构 <template>

<template>
    <div class="m-12 flex flex-col items-center justify-center gap-8 text-white">
        <h3 class="font-mono text-2xl font-bold">Frequently Asked Questions</h3>
        <div
            v-for="(item, index) in FQList"
            :key="item.id"
            class="w-2xl overflow-hidden rounded-2xl bg-gray-500 p-8">
            <div class="flex cursor-pointer items-start justify-between">
                <div class="text-xl font-bold">{{ item.question }}</div>
                <div v-if="item.isOpen" class="text-2xl font-bold" @click="currentCollapse(index)">
                    -
                </div>
                <div v-else class="text-2xl font-bold" @click="currentCollapse(index)">+</div>
            </div>
            <Transition
                enter-active-class="transition duration-500 ease-in-out"
                enter-from-class="opacity-0 -translate-y-2"
                enter-to-class="opacity-100 translate-y-0"
                leave-active-class="transition duration-200 ease-in"
                leave-from-class="opacity-100 translate-y-0"
                leave-to-class="opacity-0 -translate-y-2">
                <div v-if="item.isOpen" class="mt-4 text-xl font-bold">
                    {{ item.answer }}
                </div>
            </Transition>
        </div>
    </div>
</template>

脚本逻辑 <script setup>

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

const current = ref(0)

const currentCollapse = (index) => {
    FQList.value[index].isOpen = !FQList.value[index].isOpen
}

const FQList = ref([
    {
        id: 1,
        question: 'What is Vue.js?',
        answer: 'Vue.js is a progressive JavaScript framework for building user interfaces. It is designed to be incrementally adoptable, and can easily scale between a simple static site and a complex single-page application.',
        isOpen: false,
    },
    {
        id: 2,
        question: 'What are the main features of Vue.js?',
        answer: 'Vue.js provides reactive data binding, component-based architecture, virtual DOM rendering, and powerful tooling like Vue Router and Vuex for state management.',
        isOpen: false,
    },
    {
        id: 3,
        question: 'How does Vue 3 differ from Vue 2?',
        answer: 'Vue 3 introduces a new Composition API, improved TypeScript support, better performance with the reactivity system, and smaller bundle size compared to Vue 2.',
        isOpen: false,
    },
    {
        id: 4,
        question: 'Is Vue.js suitable for large-scale applications?',
        answer: 'Yes, Vue.js is suitable for both small projects and large-scale enterprise applications due to its modular structure, ecosystem tools, and scalability.',
        isOpen: false,
    },
])
</script>

🔍 重点效果实现

✅ 折叠面板切换逻辑

通过 currentCollapse(index) 方法控制每个条目的 isOpen 状态:

const currentCollapse = (index) => {
    FQList.value[index].isOpen = !FQList.value[index].isOpen
}

这样就能实现点击“+”或“-”按钮时切换对应面板的展开/收起状态。

🎭 过渡动画实现

我们使用 Vue 的 <Transition> 组件并自定义类名来实现动画:

<Transition
    enter-active-class="transition duration-500 ease-in-out"
    enter-from-class="opacity-0 -translate-y-2"
    enter-to-class="opacity-100 translate-y-0"
    leave-active-class="transition duration-200 ease-in"
    leave-from-class="opacity-100 translate-y-0"
    leave-to-class="opacity-0 -translate-y-2">
    <div v-if="item.isOpen" class="mt-4 text-xl font-bold">
        {{ item.answer }}
    </div>
</Transition>
  • enter-* 类控制元素进入时的动画。
  • leave-* 类控制元素离开时的动画。
  • duration-500ease-in-out 等是 Tailwind 提供的动画持续时间和缓动函数类。

🎨 TailwindCSS 样式重点讲解

类名 作用
m-12 外边距为 3rem
flex, flex-col 弹性布局并设置为纵向排列
items-center, justify-center 内容居中对齐
gap-8 子元素之间间距为 2rem
text-white 设置文字颜色为白色
font-mono 使用等宽字体
rounded-2xl 圆角大小为 1rem
bg-gray-500 设置背景颜色为灰色
p-8 内边距为 2rem
cursor-pointer 鼠标悬停时变为手型
overflow-hidden 隐藏超出容器的内容,用于动画流畅展示
text-xl, text-2xl 不同层级的文字大小
font-bold 加粗字体
mt-4 上边距为 1rem

这些 Tailwind 工具类帮助我们快速完成了一个现代、响应式的 FAQ 页面设计。


📁 常量定义 + 组件路由

constants/index.js 添加组件预览常量:

{
        id: 12,
        title: 'FAQ Collapse',
        image: 'https://50projects50days.com/img/projects-img/12-faq-collapse.png',
        link: 'FAQCollapse',
    },

router/index.js 中添加路由选项:

{
    path: '/FAQCollapse',
    name: 'FAQCollapse',
    component: () => import('@/projects/FAQCollapse.vue'),
},

🏁 总结

这个 FAQ 折叠面板组件虽然功能简单,但涵盖了 Vue 3 的响应式系统、条件渲染、事件处理以及 <Transition> 动画组件的使用,同时借助 TailwindCSS 快速实现了美观的 UI 设计。


👉 下一篇,我们将完成RandomChoicePicker组件,一个现代化的折叠Q&A面板!🚀