UniApp表单校验两种方式对比详解
作者:码农研究僧
本文对比了UniApp中表单校验的命令式和声明式两种方式,通过实战示例展示了它们的优缺点,并有详细的代码示例供大家参考,需要的朋友可以参考下
以下主要针对Demo讲解,从实战中的体会
何为命令式 何为声明式
- 命令式的体验,随时都会有提交的按钮,但是点击提交才会显示不满足的条件!
- 声明式的体验,不满足条件时,按钮框是灰色的!
命令式:
提交逻辑复杂,需要异步校验(如服务端唯一性检查)
表单字段多,依赖用户行为触发验证
需要复用校验函数,或表单逻辑分散多处声明式:
表单简单明了
用户体验优先,提前告知无法提交的情况
状态可视化,一目了然
对比项 | 命令式校验(方法中校验) | 声明式校验(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
以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表单校验方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!