uniapp动态循环表单校验失败:初始值校验
问题现象 💥
在实现动态增减的单价输入表单时(基于uv-form组件),遇到以下诡异现象:
<uv-input>
的v-model绑定初始值为数字类型时,required规则失效 ❌- 数字类型与字符串类型校验表现不一致 🔢
技术栈背景 🛠️
- 框架:Vue3 + uni-app
- UI库:uv-ui
- 校验方案:计算属性动态生成规则
示意图 🔍
解决方案 🚀
1.优先使用字符串类型做表单绑定
2.添加自定义校验规则(validator)解决初始值问题
<template>
<view class="form-box">
<uv-form ref="refForm" :model="formvalue" labelWidth="100px" :rules="rules">
<view class="form-list-item" v-for="(item, index) in formvalue.detailList" :key="index">
<uv-form-item borderBottom label="单价" :prop="`detailList.${index}.amount`" required>
<uv-input inputAlign="right" type="digit" v-model="item.amount" placeholder="请输入单价" border="none">
<template v-slot:suffix> 元 </template>
</uv-input>
</uv-form-item>
<view class="mt24" v-if="formvalue.detailList.length != 1"><uv-button plain text="移除"
@click.stop="handleDel(index)" :customStyle="{ height: '60rpx' }"></uv-button>
</view>
</view>
</uv-form>
<view class="page-footer">
<uv-button plain text="新增" @click.stop="handleAdd()"></uv-button>
<uv-button type="primary" shape="circle" text="提交" @click="onSubmit"></uv-button>
</view>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { deepClone, isEmpty } from '@/utils';
const refForm = ref(null);
const formvalue = reactive({
detailList: [],
});
const billRules = computed(() => {
let rules = {};
formvalue.detailList.forEach((item, index) => {
rules[`detailList.${index}.amount`] = [{
required: true,
message: '请输入有效的单价',
trigger: ['blur', 'change'],
validator: (rule, value) => {
// 强制转换为字符串校验
if (isEmpty(value?.toString())) return false;
const numValue = Number(value);
return !isNaN(numValue) && numValue > 0;
}
}];
})
return rules
});
const rules = computed(() => {
return {
...billRules.value
}
});
const detailObj = {
amount: 10,
}
const handleAdd = () => {
formvalue.detailList.push(deepClone(detailObj))
}
const handleDel = (index) => {
formvalue.detailList.splice(index, 1)
}
onLoad(async () => {
handleAdd()
})
const onSubmit = async () => {
refForm.value.validate().then(async () => {
})
}
</script>
<style lang="scss" scoped>
.form-box {
margin-top: 180rpx;
}
.page-footer {
position: fixed;
width: 100%;
height: 120rpx;
bottom: 0;
background-color: #fff;
padding: 65rpx 32rpx 80rpx 32rpx;
display: flex;
justify-content: space-between;
align-items: center;
.uv-button-box {
flex: 1;
margin: 0 12rpx;
}
}
</style>