Files
youbai/src/components/ui/ContactForm.vue
2025-06-09 22:19:09 +08:00

218 lines
6.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref } from 'vue'
// 表单数据
const formData = ref({
name: '',
email: '',
phone: '',
message: ''
})
// 错误信息
const errors = ref({
name: '',
email: '',
phone: '',
message: ''
})
// 表单验证
const validateForm = () => {
let isValid = true
errors.value = { name: '', email: '', phone: '', message: '' }
// 姓名验证
if (!formData.value.name.trim()) {
errors.value.name = '请输入姓名'
isValid = false
} else if (formData.value.name.length < 2) {
errors.value.name = '姓名至少需要2个字符'
isValid = false
}
// 邮箱验证
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!formData.value.email) {
errors.value.email = '请输入邮箱'
isValid = false
} else if (!emailRegex.test(formData.value.email)) {
errors.value.email = '请输入有效的邮箱地址'
isValid = false
}
// 电话验证
const phoneRegex = /^1[3-9]\d{9}$/
if (!formData.value.phone) {
errors.value.phone = '请输入电话'
isValid = false
} else if (!phoneRegex.test(formData.value.phone)) {
errors.value.phone = '请输入有效的手机号码'
isValid = false
}
// 留言验证
if (!formData.value.message.trim()) {
errors.value.message = '请输入留言内容'
isValid = false
} else if (formData.value.message.length < 10) {
errors.value.message = '留言内容至少需要10个字符'
isValid = false
}
return isValid
}
// 提交表单
const submitForm = (event: Event) => {
event.preventDefault()
if (validateForm()) {
// 在控制台打印表单值
console.log('表单提交数据:', JSON.parse(JSON.stringify(formData.value)))
// 这里可以添加实际的提交逻辑如API请求
// axios.post('/api/submit', formData.value)
// 提交成功后重置表单
formData.value = { name: '', email: '', phone: '', message: '' }
alert('表单提交成功!')
} else {
console.log('表单验证失败:', errors.value)
}
}
</script>
<template>
<div>
<form class="space-y-6" @submit="submitForm">
<!-- 姓名 -->
<div data-aos="fade-up" data-aos-delay="200">
<label for="name" class="block text-sm font-medium text-blue-200 mb-1">姓名</label>
<input
type="text"
id="name"
v-model="formData.name"
class="w-full px-4 py-2 rounded-lg border border-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-blue-900/50 text-white"
placeholder="请输入您的姓名"
:class="{ 'border-red-500': errors.name }"
>
<div v-if="errors.name" class="text-red-400 text-sm mt-1">{{ errors.name }}</div>
</div>
<!-- 邮箱 -->
<div data-aos="fade-up" data-aos-delay="250">
<label for="email" class="block text-sm font-medium text-blue-200 mb-1">邮箱</label>
<input
type="email"
id="email"
v-model="formData.email"
class="w-full px-4 py-2 rounded-lg border border-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-blue-900/50 text-white"
placeholder="请输入您的邮箱"
:class="{ 'border-red-500': errors.email }"
>
<div v-if="errors.email" class="text-red-400 text-sm mt-1">{{ errors.email }}</div>
</div>
<!-- 电话 -->
<div data-aos="fade-up" data-aos-delay="300">
<label for="phone" class="block text-sm font-medium text-blue-200 mb-1">电话</label>
<input
type="tel"
id="phone"
v-model="formData.phone"
class="w-full px-4 py-2 rounded-lg border border-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-blue-900/50 text-white"
placeholder="请输入您的电话"
:class="{ 'border-red-500': errors.phone }"
>
<div v-if="errors.phone" class="text-red-400 text-sm mt-1">{{ errors.phone }}</div>
</div>
<!-- 留言 -->
<div data-aos="fade-up" data-aos-delay="350">
<label for="message" class="block text-sm font-medium text-blue-200 mb-1">留言内容</label>
<textarea
id="message"
v-model="formData.message"
rows="4"
class="w-full px-4 py-2 rounded-lg border border-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-400 bg-blue-900/50 text-white"
placeholder="请输入您的留言内容"
:class="{ 'border-red-500': errors.message }"
></textarea>
<div v-if="errors.message" class="text-red-400 text-sm mt-1">{{ errors.message }}</div>
</div>
<!-- 提交按钮 - 优化版 -->
<button
type="submit"
class="w-full bg-gradient-to-r from-blue-500 to-indigo-600 hover:from-blue-600 hover:to-indigo-700 text-white font-medium py-3 px-6 rounded-lg flex items-center justify-center transition-all duration-300 transform hover:-translate-y-1 shadow-lg hover:shadow-xl active:translate-y-0 active:shadow-md"
data-aos="fade-up"
data-aos-delay="400"
>
<i class="fas fa-paper-plane mr-2 transform group-hover:translate-x-1 transition-transform"></i>
<span class="group-hover:font-semibold transition-all">提交申请</span>
</button>
</form>
</div>
</template>
<style scoped>
/* 添加输入框聚焦时的动画效果 */
input:focus, textarea:focus {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
transition: all 0.3s ease;
}
/* 错误提示动画 */
.text-red-400 {
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-5px); }
to { opacity: 1; transform: translateY(0); }
}
/* 按钮悬停效果 */
button {
position: relative;
overflow: hidden;
}
button::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 5px;
height: 5px;
background: rgba(255, 255, 255, 0.5);
opacity: 0;
border-radius: 100%;
transform: scale(1, 1) translate(-50%);
transform-origin: 50% 50%;
}
button:focus:not(:active)::after {
animation: ripple 1s ease-out;
}
@keyframes ripple {
0% {
transform: scale(0, 0);
opacity: 0.7;
}
100% {
transform: scale(50, 50);
opacity: 0;
}
}
/* 按钮图标动画 */
button:hover i {
transform: translateX(5px);
transition: transform 0.3s ease;
}
</style>