UniApp 表单校验两种方式对比:下令式与声明式

[复制链接]
发表于 2025-10-6 10:45:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
前言

   🤟 找工作,来万码优才:👉 #小步伐://万码优才/r6rqmzDaXpYkJZF
  以下重要针对Demo教学,从实战中的领会
作甚下令式 作甚声明式


  • 下令式的体验,随时都会有提交的按钮,但是点击提交才会表现不满意的条件!

  • 声明式的体验,不满意条件时,按钮框是灰色的!


  • 下令式:
    提交逻辑复杂,须要异步校验(如服务端唯一性查抄)
    表单字段多,依赖用户活动触发验证
    须要复用校验函数,或表单逻辑分散多处
  • 声明式:
    表单简朴明白
    用户体验优先,提前告知无法提交的情况
    状态可视化,一清二楚
对比项下令式校验(方法中校验)声明式校验(computed + disabled 控制)📋 方式在 submit() 方法内通过 validateForm() 显式校验通过 computed 盘算属性及时判断是否可提交🧠 编程范式下令式(Imperative)声明式(Declarative)💡 表达方式手动控制流程:如果失败就 return false自动盘算状态:按钮根据是否满意条件自动禁用🔁 可复用性校验逻辑聚焦在 validateForm(),但要手动调用校验逻辑绑定在状态中,按钮等 UI 自动相应🧪 用户体验用户点击“提交”后才提示不通过一清二楚,提交按钮禁用,无法误触提交⚙️ 机动性可以机动插入额外逻辑,如提交前弹窗确认逻辑得当纯状态驱动,复杂流程需别的处理惩罚🪛 实用场景须要流程控制、嵌套逻辑、异步校验时更得当表单项简朴明白、状态驱动时更得当1. 实战

实战中抽取的Demo比力浅近:
下令式 submit 校验方式(validateForm)
  1. <template>
  2.   <button type="primary" @click="submit">提交</button>
  3. </template>
  4. <script>
  5. export default {
  6.   data() {
  7.     return {
  8.       imgCntrF: [],
  9.       damPhotoList: []
  10.     };
  11.   },
  12.   methods: {
  13.     validateForm() {
  14.       if (!this.imgCntrF.length) {
  15.         uni.showToast({ title: '请拍摄箱门照片', icon: 'none' });
  16.         return false;
  17.       }
  18.       if (this.damPhotoList.length < 2) {
  19.         uni.showToast({ title: '请至少拍摄 2 张照片', icon: 'none' });
  20.         return false;
  21.       }
  22.       return true;
  23.     },
  24.     async submit() {
  25.       if (!this.validateForm()) return;
  26.       // 执行提交逻辑
  27.       console.log("提交成功");
  28.     }
  29.   }
  30. }
  31. </script>
复制代码
声明式 computed 控制按钮状态
  1. <template>
  2.   <button type="primary" :disabled="!canSubmit" @click="submit">提交</button>
  3. </template>
  4. <script>
  5. export default {
  6.   data() {
  7.     return {
  8.       photoList: {
  9.         door: '',  // 对应 imgCntrF
  10.         side: ''
  11.       },
  12.       damPhotoList: [],
  13.       photoField: [
  14.         { key: 'door', label: '箱门照片' },
  15.         { key: 'side', label: '侧面照片' }
  16.       ]
  17.     };
  18.   },
  19.   computed: {
  20.     canSubmit() {
  21.       return this.photoField.every(field => this.photoList[field.key]) &&
  22.              this.damPhotoList.length >= 2;
  23.     }
  24.   },
  25.   methods: {
  26.     submit() {
  27.       console.log("提交成功");
  28.     }
  29.   }
  30. }
  31. </script>
复制代码
2. Demo

以UniApp( Vue2 语法 + script 写法)
下令式校验提交(Imperative)
  1. <template>
  2.   <view class="container">
  3.     <view class="section">
  4.       <text>箱门照片:</text>
  5.       <button @click="selectBoxDoorPhoto">选择照片</button>
  6.       <image v-if="imgCntrF" :src="imgCntrF" class="img-preview" />
  7.     </view>
  8.     <view class="section">
  9.       <text>破损照片:</text>
  10.       <button @click="addDamPhoto">添加照片</button>
  11.       <view class="photo-list">
  12.         <image v-for="(photo, index) in damPhotoList" :key="index" :src="photo" class="img-preview" />
  13.       </view>
  14.     </view>
  15.     <button type="primary" @click="submit">提交</button>
  16.   </view>
  17. </template>
  18. <script>
  19. export default {
  20.   data() {
  21.     return {
  22.       imgCntrF: '', // 箱门照片 URL
  23.       damPhotoList: [] // 破损照片 URL 列表
  24.     };
  25.   },
  26.   methods: {
  27.     selectBoxDoorPhoto() {
  28.       uni.chooseImage({
  29.         count: 1,
  30.         success: (res) => {
  31.           this.imgCntrF = res.tempFilePaths[0];
  32.         }
  33.       });
  34.     },
  35.     addDamPhoto() {
  36.       uni.chooseImage({
  37.         count: 1,
  38.         success: (res) => {
  39.           this.damPhotoList.push(res.tempFilePaths[0]);
  40.         }
  41.       });
  42.     },
  43.     validateForm() {
  44.       if (!this.imgCntrF) {
  45.         uni.showToast({ title: '请拍摄箱门照片', icon: 'none' });
  46.         return false;
  47.       }
  48.       if (this.damPhotoList.length < 2) {
  49.         uni.showToast({ title: '请至少拍摄 2 张破损照片', icon: 'none' });
  50.         return false;
  51.       }
  52.       return true;
  53.     },
  54.     submit() {
  55.       if (!this.validateForm()) return;
  56.       // 模拟提交成功
  57.       uni.showToast({ title: '提交成功', icon: 'success' });
  58.     }
  59.   }
  60. };
  61. </script>
  62. <style>
  63. .container {
  64.   padding: 20rpx;
  65. }
  66. .section {
  67.   margin-bottom: 30rpx;
  68. }
  69. .img-preview {
  70.   width: 200rpx;
  71.   height: 200rpx;
  72.   margin-top: 10rpx;
  73. }
  74. .photo-list {
  75.   display: flex;
  76.   flex-wrap: wrap;
  77.   gap: 10rpx;
  78. }
  79. </style>
复制代码
声明式按钮控制提交(Declarative)
  1. <template>
  2.   <view class="container">
  3.     <view class="section">
  4.       <text>箱门照片:</text>
  5.       <button @click="selectBoxDoorPhoto">选择照片</button>
  6.       <image v-if="photoList.door" :src="photoList.door" class="img-preview" />
  7.     </view>
  8.     <view class="section">
  9.       <text>破损照片:</text>
  10.       <button @click="addDamPhoto">添加照片</button>
  11.       <view class="photo-list">
  12.         <image v-for="(photo, index) in damPhotoList" :key="index" :src="photo" class="img-preview" />
  13.       </view>
  14.     </view>
  15.     <button type="primary" :disabled="!canSubmit" @click="submit">提交</button>
  16.   </view>
  17. </template>
  18. <script>
  19. export default {
  20.   data() {
  21.     return {
  22.       photoList: {
  23.         door: '' // 箱门照片
  24.       },
  25.       damPhotoList: []
  26.     };
  27.   },
  28.   computed: {
  29.     canSubmit() {
  30.       return !!this.photoList.door && this.damPhotoList.length >= 2;
  31.     }
  32.   },
  33.   methods: {
  34.     selectBoxDoorPhoto() {
  35.       uni.chooseImage({
  36.         count: 1,
  37.         success: (res) => {
  38.           this.photoList.door = res.tempFilePaths[0];
  39.         }
  40.       });
  41.     },
  42.     addDamPhoto() {
  43.       uni.chooseImage({
  44.         count: 1,
  45.         success: (res) => {
  46.           this.damPhotoList.push(res.tempFilePaths[0]);
  47.         }
  48.       });
  49.     },
  50.     submit() {
  51.       uni.showToast({ title: '提交成功', icon: 'success' });
  52.     }
  53.   }
  54. };
  55. </script>
  56. <style>
  57. .container {
  58.   padding: 20rpx;
  59. }
  60. .section {
  61.   margin-bottom: 30rpx;
  62. }
  63. .img-preview {
  64.   width: 200rpx;
  65.   height: 200rpx;
  66.   margin-top: 10rpx;
  67. }
  68. .photo-list {
  69.   display: flex;
  70.   flex-wrap: wrap;
  71.   gap: 10rpx;
  72. }
  73. </style>
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表