Files
YGChatCS/components/FormCard
2025-08-03 18:06:06 +08:00
..
2025-07-15 16:48:32 +08:00
2025-08-03 18:06:06 +08:00
2025-08-03 18:06:06 +08:00
2025-08-03 18:06:06 +08:00
2025-07-15 16:48:32 +08:00
2025-08-03 18:06:06 +08:00

FormCard 表单卡片组件

一个功能完整的表单卡片组件,支持姓名和手机号输入,具备数据验证和双向绑定功能。

功能特性

  • 📝 双向绑定:支持 v-model 双向数据绑定
  • 数据验证:内置手机号格式验证
  • 🎨 自定义标题:可配置游客标题文本
  • 🗑️ 删除功能:支持删除操作,可配置显示/隐藏
  • 💫 交互反馈:输入框聚焦效果和错误状态提示
  • 📱 响应式设计:适配不同屏幕尺寸
  • 🎯 事件支持:完整的事件系统
  • 性能优化:使用计算属性优化渲染

基础用法

默认使用

<template>
  <FormCard 
    :form="form"
    @update:name="form.name = $event"
    @update:phone="form.phone = $event"
    @delete="handleDelete"
  />
</template>

<script setup>
import { reactive } from 'vue'
import FormCard from '@/components/FormCard/index.vue'

const form = reactive({
  name: '',
  phone: ''
})

const handleDelete = () => {
  console.log('删除表单')
}
</script>

自定义标题

<template>
  <FormCard 
    :form="form"
    title="成人票"
    @update:name="form.name = $event"
    @update:phone="form.phone = $event"
    @delete="handleDelete"
  />
</template>

隐藏删除图标

<template>
  <FormCard 
    :form="form"
    title="联系人信息"
    :show-delete-icon="false"
    @update:name="form.name = $event"
    @update:phone="form.phone = $event"
  />
</template>

多个表单卡片

<template>
  <view>
    <FormCard 
      v-for="(item, index) in formList"
      :key="index"
      :form="item"
      :title="`游客${index + 1}`"
      @update:name="item.name = $event"
      @update:phone="item.phone = $event"
      @delete="handleDeleteForm(index)"
    />
    <button @click="addForm">添加游客</button>
  </view>
</template>

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

const formList = ref([
  { name: '', phone: '' },
  { name: '', phone: '' }
])

const handleDeleteForm = (index) => {
  formList.value.splice(index, 1)
}

const addForm = () => {
  formList.value.push({ name: '', phone: '' })
}
</script>

表单验证

<template>
  <FormCard 
    ref="formCardRef"
    :form="form"
    title="验证示例"
    @update:name="form.name = $event"
    @update:phone="form.phone = $event"
  />
  <button @click="validateForm">验证表单</button>
</template>

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

const formCardRef = ref()
const form = reactive({
  name: '',
  phone: ''
})

const validateForm = () => {
  // 手动触发验证
  formCardRef.value.validateName()
  formCardRef.value.validatePhone()
  
  // 或者使用工具函数检查
  const nameError = formCardRef.value.getNameError(form.name)
  const phoneError = formCardRef.value.getPhoneError(form.phone)
  
  if (!nameError && !phoneError) {
    console.log('表单验证通过')
  }
}
</script>

API 文档

Props

参数 类型 默认值 说明
title String "游客1" 表单卡片标题
form Object { name: '', phone: '' } 表单数据对象,包含 name 和 phone 字段
form.name String "" 姓名值
form.phone String "" 手机号值
showDeleteIcon Boolean true 是否显示删除图标

Events

事件名 参数 说明
update:name (value: string) 姓名值更新时触发,自动去除首尾空格
update:phone (value: string) 手机号值更新时触发,自动过滤非数字字符
delete - 点击删除图标时触发

Methods (通过 ref 调用)

方法名 参数 返回值 说明
validateName - void 手动触发姓名验证
validatePhone - void 手动触发手机号验证
getNameError (name: string) string 获取姓名验证错误信息
getPhoneError (phone: string) string 获取手机号验证错误信息

数据验证

组件内置完整的表单验证:

  • 姓名验证:不能为空,自动去除首尾空格
  • 手机号验证支持中国大陆手机号格式1开头第二位为3-9总长度11位
  • 失焦验证:只在输入框失去焦点时进行验证,避免输入干扰
  • 错误提示:验证失败时显示错误信息,带有淡入动画效果
  • 视觉反馈:输入框边框变红提示错误状态
  • 自动过滤:手机号输入时自动过滤非数字字符

样式定制

CSS 变量系统

组件使用 CSS 变量系统,支持主题定制:

:root {
  --form-primary-color: #00a6ff;        // 主色调
  --form-error-color: #ff4d4f;          // 错误色
  --form-text-color: #333;              // 文本色
  --form-label-color: #86909c;          // 标签色
  --form-border-color: #e5e8ef;         // 边框色
  --form-input-border-color: #ddd;      // 输入框边框色
  --form-bg-color: #fff;                // 背景色
  --form-header-bg-color: rgba(25, 144, 255, 0.06); // 头部背景色
  --form-border-radius: 8px;            // 圆角大小
  --form-transition: all 0.2s ease;     // 过渡动画
}

主要样式类

.form-wrapper {
  // 表单容器,支持悬停效果和阴影
}

.form-header {
  // 表单头部,包含标题和删除按钮
}

.form-title {
  // 标题文本,支持文本溢出省略
}

.form-item {
  // 表单项容器,支持分隔线
}

.form-input {
  // 输入框,支持聚焦和错误状态
}

.form-error {
  // 错误信息,带有淡入动画
}

响应式设计

组件内置响应式支持,在小屏幕设备上自动调整:

  • 320px 以下设备优化布局
  • 自动调整字体大小和间距
  • 保持良好的可用性

自定义主题

通过覆盖 CSS 变量来自定义主题:

// 自定义主题色
:root {
  --form-primary-color: #your-primary-color;
  --form-error-color: #your-error-color;
  --form-border-radius: 12px;
}

// 或者针对特定组件
.your-custom-form {
  --form-primary-color: #your-primary-color;
  --form-header-bg-color: rgba(your-color, 0.1);
}

高级用法

表单验证集成

<template>
  <FormCard 
    ref="formCardRef"
    :form="form"
    title="游客信息"
    @update:name="form.name = $event"
    @update:phone="form.phone = $event"
    @delete="handleDelete"
  />
  <button @click="validateForm">提交</button>
</template>

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

const formCardRef = ref()
const form = reactive({
  name: '',
  phone: ''
})

const validateForm = () => {
  // 使用组件内置的验证方法
  const nameError = formCardRef.value.getNameError(form.name)
  const phoneError = formCardRef.value.getPhoneError(form.phone)
  
  if (nameError) {
    uni.showToast({
      title: nameError,
      icon: 'none'
    })
    return
  }
  
  if (phoneError) {
    uni.showToast({
      title: phoneError,
      icon: 'none'
    })
    return
  }
  
  // 提交表单
  console.log('表单数据:', form)
}
</script>

动态表单管理

<template>
  <view>
    <FormCard 
      v-for="(item, index) in passengers"
      :key="item.id"
      :form="item"
      @update:name="item.name = $event"
      @update:phone="item.phone = $event"
      :title="getPassengerTitle(item.type, index)"
      :show-delete-icon="passengers.length > 1"
      @delete="removePassenger(index)"
    />
    
    <view class="action-buttons">
      <button @click="addAdult">添加成人</button>
      <button @click="addChild">添加儿童</button>
    </view>
  </view>
</template>

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

const passengers = ref([
  { id: 1, type: 'adult', name: '', phone: '' }
])

let nextId = 2

const getPassengerTitle = (type, index) => {
  return type === 'adult' ? `成人${index + 1}` : `儿童${index + 1}`
}

const addAdult = () => {
  passengers.value.push({
    id: nextId++,
    type: 'adult',
    name: '',
    phone: ''
  })
}

const addChild = () => {
  passengers.value.push({
    id: nextId++,
    type: 'child',
    name: '',
    phone: ''
  })
}

const removePassenger = (index) => {
  if (passengers.value.length > 1) {
    passengers.value.splice(index, 1)
  }
}
</script>

注意事项

  1. 数据传递:使用 :form 对象传递数据,包含 namephone 字段
  2. 双向绑定:通过 @update:name@update:phone 事件进行双向绑定
  3. 验证机制:只在失去焦点时进行验证,避免输入干扰
  4. 手机号验证仅支持中国大陆手机号格式验证1开头第二位3-9总长度11位
  5. 自动处理:手机号自动过滤非数字字符,姓名自动去除首尾空格
  6. 删除功能:删除事件需要父组件处理具体逻辑
  7. 方法调用:通过 ref 可调用组件内部的验证方法
  8. 兼容性支持微信小程序、H5、App等平台

更新日志

v1.3.0 (2024-12-19)

性能与可维护性全面优化

  • 🚀 性能优化:提取常量定义,优化计算属性逻辑
  • 🛠️ 代码重构:添加完整的 JSDoc 注释和类型定义
  • 🎨 样式升级:使用 CSS 变量系统,支持主题定制
  • 功能增强:手机号自动过滤非数字字符,姓名自动去除空格
  • 🎭 UI 改进:新增悬停效果、错误信息动画和阴影效果
  • 📱 响应式设计:优化小屏幕设备适配
  • 🔧 开发体验:添加 defineExpose 暴露验证方法,便于测试
  • 📝 文档完善:更新演示和使用说明

v1.2.3 (2024-12-19)

优化验证行为

  • 🎨 优化验证行为,移除实时验证
  • 姓名和手机号只在失去焦点时进行验证
  • 🔧 移除不必要的 watch 监听器
  • 📝 更新文档和演示说明
  • 提升组件性能和用户体验

v1.2.2 (2024-12-19)

新增姓名验证功能

  • 新增姓名非空验证功能
  • 👤 姓名为空时显示"请输入姓名"提示
  • 🔄 支持姓名实时验证,输入内容时错误信息自动隐藏
  • 🎯 完善表单验证体系,提升数据完整性
  • 💫 优化用户体验,提供友好的输入提示

v1.2.1 (2024-12-19)

优化手机号验证功能

  • 🐛 修复validatePhone方法中props引用错误的问题
  • 新增手机号实时验证功能
  • 🔄 输入正确手机号时错误信息自动隐藏
  • 📱 优化用户输入体验,提供即时反馈
  • 🎯 完善demo页面增加功能说明

v1.2.0 (2024-12-19)

新增删除功能

  • 支持删除表单卡片
  • 🎯 可配置删除图标显示/隐藏
  • 🔄 完善事件系统支持delete事件
  • 💫 优化用户交互体验

v2.0.0

  • 重构组件,支持 props 传值和双向绑定
  • 新增 title 属性,支持自定义标题
  • 新增 showDeleteIcon 属性,控制删除图标显示
  • 新增完整的事件系统update:name, update:phone, delete
  • 🎨 优化样式,新增错误状态和交互效果
  • 🔧 改进手机号验证逻辑
  • 📝 新增完整的文档和演示示例

v1.0.0

  • 🎉 初始版本发布
  • 基础表单功能
  • 手机号验证
  • 基础样式

技术栈

  • Vue 3 Composition API
  • SCSS
  • uni-app

浏览器支持

  • 微信小程序
  • H5 (Chrome, Firefox, Safari, Edge)
  • App (iOS, Android)

许可证

MIT License