📅 我们继续 50 个小项目挑战!—— FeedbackUiDesign
组件
仓库地址:https://github.com/SunACong/50-vue-projects
项目预览地址:https://50-vue-projects.vercel.app/
使用 Vue 3 的 <script setup>
语法结合 Tailwind CSS 来构建一个美观且交互性强的用户满意度评分组件。这个组件允许用户通过点击表情图标来选择他们的满意度等级,并在提交后显示感谢信息,非常适合用于收集客户反馈、产品评价或服务评分。
让我们开始吧!🚀
📝 应用目标
- 使用 Vue 3 Composition API 管理组件状态
- 实现可点击的评分选项,支持视觉反馈(悬停、选中效果)
- 展示提交前后的不同界面状态
- 利用 Tailwind CSS 快速构建现代化、响应式的 UI
- 提供流畅的用户体验和动画效果
🔧 技术实现点
技术点 | 描述 |
---|---|
Vue 3 <script setup> | 使用 ref 定义响应式数据和事件处理函数 |
v-for 循环渲染 | 动态生成评分选项 |
v-if / v-else 条件渲染 | 根据是否提交切换显示不同的面板 |
@click 事件监听 | 处理用户点击评分和提交按钮 |
:class 动态绑定 | 根据选中状态应用不同的样式 |
transition-all duration-200 | 添加平滑的过渡动画 |
active:scale-98 | 点击时的轻微缩小效果,增强触觉反馈 |
🖌️ 组件实现
🎨 模板结构 <template>
<template>
<div class="flex min-h-screen items-center justify-center bg-gray-100 p-4 font-sans">
<!-- 主面板容器 (提交前) -->
<div
class="w-full max-w-md rounded-lg bg-white p-8 text-center shadow-md"
v-if="!isSubmitted">
<strong class="leading-relaxed text-gray-800">
How satisfied are you with our
<br />
customer support performance?
</strong>
<!-- 评分选项容器 -->
<div class="my-8 flex justify-center">
<div
v-for="rating in ratings"
:key="rating.id"
@click="selectRating(rating.value)"
:class="[
'flex cursor-pointer flex-col items-center rounded-md p-5 transition-all duration-200',
selectedRating === rating.value
? 'scale-110 bg-white shadow-lg'
: 'hover:bg-gray-50',
]">
<img :src="rating.imgUrl" :alt="rating.label" class="mb-3 h-10 w-10" />
<small class="text-gray-600">{{ rating.label }}</small>
</div>
</div>
<!-- 提交按钮 -->
<button
@click="submitFeedback"
class="rounded-md bg-gray-800 px-8 py-3 text-white transition-all duration-200 hover:bg-gray-700 active:scale-98">
Send Review
</button>
</div>
<!-- 提交后的感谢面板 -->
<div class="w-full max-w-md rounded-lg bg-white p-8 text-center shadow-md" v-else>
<i class="fas fa-heart mb-4 text-4xl text-red-500"></i>
<strong class="mb-1 block text-xl text-gray-800">Thank You!</strong>
<strong class="mb-2 text-gray-700">Feedback: {{ selectedRating }}</strong>
<p class="text-sm text-gray-500">
We'll use your feedback to improve our customer support
</p>
</div>
</div>
</template>
模板部分清晰地分为两个主要状态:
-
提交前状态 (
v-if="!isSubmitted"
)- 标题:使用
<strong>
标签显示询问用户满意度的问题。 - 评分选项:使用
v-for
遍历ratings
数组生成三个可点击的选项。每个选项包含一个表情图标和标签文字。@click
事件绑定到selectRating
函数。 - 动态样式:
:class
绑定根据selectedRating
是否等于当前评分的value
来决定应用哪种样式。选中时放大 (scale-110
) 并添加阴影 (shadow-lg
);未选中时悬停 (hover:bg-gray-50
) 有轻微背景色变化。 - 提交按钮:点击后触发
submitFeedback
函数。
- 标题:使用
-
提交后状态 (
v-else
)- 显示一个感谢界面,包含一个爱心图标(使用 Font Awesome)、感谢语、用户选择的反馈值以及一段说明文字。
💻 脚本逻辑 <script setup>
<script setup>
import { ref } from 'vue'
// 响应式状态
const selectedRating = ref('Satisfied') // 默认选中Satisfied
const isSubmitted = ref(false)
// 评分选项数据
const ratings = ref([
{
id: 1,
imgUrl: 'https://img.icons8.com/external-neu-royyan-wijaya/64/000000/external-emoji-neumojis-smiley-neu-royyan-wijaya-17.png',
label: 'Unhappy',
value: 'Unhappy',
},
{
id: 2,
imgUrl: 'https://img.icons8.com/external-neu-royyan-wijaya/64/000000/external-emoji-neumojis-smiley-neu-royyan-wijaya-3.png',
label: 'Neutral',
value: 'Neutral',
},
{
id: 3,
imgUrl: 'https://img.icons8.com/external-neu-royyan-wijaya/64/000000/external-emoji-neumojis-smiley-neu-royyan-wijaya-30.png',
label: 'Satisfied',
value: 'Satisfied',
},
])
// 选择评分
const selectRating = (rating) => {
selectedRating.value = rating
}
// 提交反馈
const submitFeedback = () => {
isSubmitted.value = true
}
</script>
脚本部分定义了组件的核心逻辑:
- 状态定义:
selectedRating
存储用户选择的评分值,isSubmitted
控制面板的显示状态。 - 数据定义:
ratings
数组包含了三个评分选项的详细信息,包括图标 URL、显示标签和内部值。 - 事件处理:
selectRating(rating)
:当用户点击某个评分选项时,将selectedRating
更新为该选项的value
。submitFeedback()
:当用户点击“Send Review”按钮时,将isSubmitted
设置为true
,从而切换到感谢面板。
🎨 Tailwind CSS 样式重点
类名 | 作用 |
---|---|
flex | 启用 Flexbox 布局 |
min-h-screen | 最小高度为视口高度,确保内容垂直居中 |
items-center / justify-center | Flex 项目在主轴和交叉轴上居中 |
bg-gray-100 | 浅灰色背景 |
p-4 | 内边距 |
font-sans | 无衬线字体 |
w-full max-w-md | 宽度占满,但最大宽度限制为 md (28rem) |
rounded-lg | 中等圆角 |
bg-white | 白色背景 |
p-8 | 较大的内边距 |
text-center | 文本居中 |
shadow-md | 中等阴影 |
leading-relaxed | 较宽松的行高 |
text-gray-800 / text-gray-600 / text-gray-500 / text-gray-700 | 不同深浅的灰色文字 |
my-8 | 上下外边距 |
justify-center | Flex 容器内项目居中对齐 |
cursor-pointer | 鼠标指针变为手型 |
flex-col | Flex 方向为垂直 |
p-5 | 内边距 |
transition-all duration-200 | 所有属性变化在 200ms 内平滑过渡 |
scale-110 | 放大到 110% |
bg-white shadow-lg | 选中时的背景和更强阴影 |
hover:bg-gray-50 | 悬停时的浅灰色背景 |
mb-3 | 下边距 |
h-10 w-10 | 图标固定大小 |
rounded-md | 按钮圆角 |
bg-gray-800 / bg-gray-700 | 按钮背景色及悬停色 |
px-8 py-3 | 按钮内边距 |
text-white | 白色文字 |
hover:bg-gray-700 | 悬停时按钮颜色变浅 |
active:scale-98 | 按下时轻微缩小 |
text-4xl | 大号文字(爱心图标) |
text-red-500 | 红色文字 |
block | 块级元素 |
text-xl | 大号文字 |
📁 常量定义 + 组件路由
{
id: 43,
title: 'FeedbackUiDesign',
image: 'https://50projects50days.com/img/projects-img/43-feedback-ui-design.png',
link: 'FeedbackUiDesign',
},
router/index.js
中添加路由选项:
{
path: '/FeedbackUiDesign',
name: 'FeedbackUiDesign',
component: () => import('@/projects/FeedbackUiDesign.vue'),
},
🏁 总结
在这篇教程中,我们成功创建了一个直观、美观且交互性良好的用户反馈评分组件。
想要让你的反馈组件更加强大?考虑以下扩展功能:
- ✅ 提交到后端:在
submitFeedback
函数中添加fetch
或axios
请求,将selectedRating
发送到服务器保存。 - ✅ 输入框收集详细反馈:在提交前,增加一个
<textarea>
让用户输入更详细的反馈意见。 - ✅ 动画效果:为面板切换或图标添加更丰富的动画(例如使用
vue-transition
)。 - ✅ 自定义图标:使用本地 SVG 图标或不同的图标库替换现有的表情图片。
- ✅ 评分重置:在感谢面板添加一个“再次评分”按钮,允许用户重新选择。
- ✅ 本地存储:使用
localStorage
记住用户之前的评分(如果需要)。
👉 下一篇,我们将完成RangeSlider
组件,一个可以自定义的范围滑块组件。🚀
感谢阅读,欢迎点赞、收藏和分享 😊