UniApp表单校验:命令式与声明式实战对比

作者:青山有信

时间:2026-10-31

浏览:147

本文对比UniApp中两种表单校验方式:命令式与声明式。命令式通过submit方法内validateForm显式校验,适合复杂逻辑和异步检查;声明式利用computed计算属性控制按钮disabled状态,实现实时反馈。通过Vue2语法Demo展示代码实现,分析各自适用场景与用户体验差异,帮助开发者选择合适方案。

文章目录

本文主要基于实际开发中的Demo案例进行讲解,分享实战经验。

首先明确概念:什么是命令式,什么是声明式。

  • 在命令式模式下,提交按钮始终可用,只有点击提交后,才会提示不满足条件的字段。

1. 实战分析

  • 在声明式模式下,当条件不满足时,提交按钮会呈现灰色禁用状态。

1. 实战分析

  1. 命令式校验适用于以下场景:提交逻辑复杂,涉及异步校验(如服务端唯一性检查);表单字段较多,依赖用户行为触发验证;需要复用校验函数,或表单逻辑分散在多处。

  2. 声明式校验适用于以下场景:表单结构简单明了;优先考虑用户体验,提前告知无法提交的情况;状态可视化,让用户一目了然。

对比项命令式校验(方法中校验)声明式校验(computed + disabled 控制)
方式在 submit() 方法内通过 validateForm() 显式校验通过 computed 计算属性实时判断是否可提交
编程范式命令式(Imperative)声明式(Declarative)
表达方式手动控制流程:如果失败就 return false自动计算状态:按钮根据是否满足条件自动禁用
可复用性校验逻辑聚焦在 validateForm(),但要手动调用校验逻辑绑定在状态中,按钮等 UI 自动响应
用户体验用户点击“提交”后才提示不通过一目了然,提交按钮禁用,无法误触提交
灵活性可以灵活插入额外逻辑,如提交前弹窗确认逻辑适合纯状态驱动,复杂流程需另外处理
适用场景需要流程控制、嵌套逻辑、异步校验时更适合表单项简单明确、状态驱动时更适合

1. 实战分析

从实际项目中抽取的Demo较为简易,旨在说明核心逻辑。

命令式submit校验方式(validateForm)的实现逻辑如下。

<template>
  <button type="primary" @click="submit">提交</button>
</template>

<script>
export default {
  data() {
    return {
      imgCntrF: [],
      damPhotoList: []
    };
  },
  methods: {
    validateForm() {
      if (!this.imgCntrF.length) {
        uni.showToast({ title: '请拍摄箱门照片', icon: 'none' });
        return false;
      }
      if (this.damPhotoList.length < 2) {
        uni.showToast({ title: '请至少拍摄 2 张照片', icon: 'none' });
        return false;
      }
      return true;
    },
    async submit() {
      if (!this.validateForm()) return;
      // 执行提交逻辑
      console.log("提交成功");
    }
  }
}
</script>

声明式computed控制按钮状态的实现逻辑如下。

<template>
  <button type="primary" :disabled="!canSubmit" @click="submit">提交</button>
</template>

<script>
export default {
  data() {
    return {
      photoList: {
        door: '',  // 对应 imgCntrF
        side: ''
      },
      damPhotoList: [],
      photoField: [
        { key: 'door', label: '箱门照片' },
        { key: 'side', label: '侧面照片' }
      ]
    };
  },
  computed: {
    canSubmit() {
      return this.photoField.every(field => this.photoList[field.key]) &&
             this.damPhotoList.length >= 2;
    }
  },
  methods: {
    submit() {
      console.log("提交成功");
    }
  }
}
</script>

2. Demo代码示例

以下Demo基于UniApp,采用Vue2语法及script写法。

命令式校验提交(Imperative)的代码实现。

<template>
  <view class="container">
    <view class="section">
      <text>箱门照片:</text>
      <button @click="selectBoxDoorPhoto">选择照片</button>
      <image v-if="imgCntrF" :src="imgCntrF" class="img-preview" />
    </view>

    <view class="section">
      <text>破损照片:</text>
      <button @click="addDamPhoto">添加照片</button>
      <view class="photo-list">
        <image v-for="(photo, index) in damPhotoList" :key="index" :src="photo" class="img-preview" />
      </view>
    </view>

    <button type="primary" @click="submit">提交</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      imgCntrF: '', // 箱门照片 URL
      damPhotoList: [] // 破损照片 URL 列表
    };
  },
  methods: {
    selectBoxDoorPhoto() {
      uni.chooseImage({
        count: 1,
        success: (res) => {
          this.imgCntrF = res.tempFilePaths[0];
        }
      });
    },
    addDamPhoto() {
      uni.chooseImage({
        count: 1,
        success: (res) => {
          this.damPhotoList.push(res.tempFilePaths[0]);
        }
      });
    },
    validateForm() {
      if (!this.imgCntrF) {
        uni.showToast({ title: '请拍摄箱门照片', icon: 'none' });
        return false;
      }
      if (this.damPhotoList.length < 2) {
        uni.showToast({ title: '请至少拍摄 2 张破损照片', icon: 'none' });
        return false;
      }
      return true;
    },
    submit() {
      if (!this.validateForm()) return;

      // 模拟提交成功
      uni.showToast({ title: '提交成功', icon: 'success' });
    }
  }
};
</script>

<style>
.container {
  padding: 20rpx;
}
.section {
  margin-bottom: 30rpx;
}
.img-preview {
  width: 200rpx;
  height: 200rpx;
  margin-top: 10rpx;
}
.photo-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10rpx;
}
</style>

声明式按钮控制提交(Declarative)的代码实现。

<template>
  <view class="container">
    <view class="section">
      <text>箱门照片:</text>
      <button @click="selectBoxDoorPhoto">选择照片</button>
      <image v-if="photoList.door" :src="photoList.door" class="img-preview" />
    </view>

    <view class="section">
      <text>破损照片:</text>
      <button @click="addDamPhoto">添加照片</button>
      <view class="photo-list">
        <image v-for="(photo, index) in damPhotoList" :key="index" :src="photo" class="img-preview" />
      </view>
    </view>

    <button type="primary" :disabled="!canSubmit" @click="submit">提交</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      photoList: {
        door: '' // 箱门照片
      },
      damPhotoList: []
    };
  },
  computed: {
    canSubmit() {
      return !!this.photoList.door && this.damPhotoList.length >= 2;
    }
  },
  methods: {
    selectBoxDoorPhoto() {
      uni.chooseImage({
        count: 1,
        success: (res) => {
          this.photoList.door = res.tempFilePaths[0];
        }
      });
    },
    addDamPhoto() {
      uni.chooseImage({
        count: 1,
        success: (res) => {
          this.damPhotoList.push(res.tempFilePaths[0]);
        }
      });
    },
    submit() {
      uni.showToast({ title: '提交成功', icon: 'success' });
    }
  }
};
</script>

<style>
.container {
  padding: 20rpx;
}
.section {
  margin-bottom: 30rpx;
}
.img-preview {
  width: 200rpx;
  height: 200rpx;
  margin-top: 10rpx;
}
.photo-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10rpx;
}
</style>

至此,关于UniApp表单校验两种方式的对比详解介绍完毕。如需了解更多UniApp表单校验相关内容,请搜索本站历史文章或继续浏览后续文章,感谢支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章