目录

问题

原因

代码分析

关键所在

解决方案


问题

使用uniapp开发vue项目移动端功能,出现该报错

原因

uView 表单要求 model 必须包含所有需要校验的字段,空对象 {} 无法满足,表单字段的初始值应该与 formSchema 中定义的字段保持一致。

代码分析

1. formData 初始化为空对象

const formData = ref({})

formData 只是一个空对象 {},而 uView 表单组件在设置 rules 时,要求 model 必须包含所有需要校验的字段。

2. formSchema 中有 defaultValue 但 formData 未初始化

{
    field: 'acquisitionTime',
    component: 'TimeSelect',
    label: '采集时间',
    defaultValue: dayjs(),
    componentProps: {
        disabled: formReadonly.value,
        format: 'YYYY-MM-DD  HH:mm:ss',
    }
}

3. 表单校验规则已定义

const formRules = ref({
    unitProject: [{ required: true, ... }],
    reportNumber: [{ required: true, ... }],
    // ...
});

4.onLoad - 异步执行

onLoad(async (options) => {  // ⚠️ 注意这里有 async
    userInfo.value = useUserStore().getUserInfo
    pageOptions.value = getDecodeOptions(options)
    if (options.id) {
        formData.value.id = options.id
    } else {
        // ...
        formData.value = {
            ...record.value,
        }
        applicationList.value = await getApplicationList()  // ⚠️ 这里有 await
        // ...
    }
})
  1. onLoad 含有异步操作
  2. 在异步等待期间,表单组件已经开始渲染
  3. 此时 formData 仍然是空对象 {},导致 uView 报错

根本原因:async 的 onLoad 使得表单在 formData 被正确赋值前就开始渲染,导致 uView 校验失败。

关键所在

正常情况下:onLoad 同步执行 → formData 赋值 → 表单渲染

我的问题在于:onLoad 开始 → 表单开始渲染(formData 为空)→ 报错

解决方案

方案一:初始化 formData

const formData = ref({
    unitProject: '',
    reportNumber: '',
    testReportNumber: '',
    // ... 其他字段
})

方案二:使用 v-if 控制表单渲染时机(未测试)

<BasicForm 
    v-if="isFormReady"
    ref="formRef" 
    v-model="formData" 
    :formSchema="formSchema" 
    :formRules="formRules">
</BasicForm>
const isFormReady = ref(false)

onLoad(async (options) => {
    // ... 其他逻辑
    applicationList.value = await getApplicationList()
    // ... 
    
    isFormReady.value = true  // 数据准备好后再渲染表单
})

方案三:将异步加载方法移至onMounted生命周期(推荐)

onLoad((options) => {
    userInfo.value = useUserStore().getUserInfo
    pageOptions.value = getDecodeOptions(options)
    if (options.id) {
        formData.value.id = options.id
    } else {
        // ...
        formData.value = {
            ...record.value,
        }
        // applicationList.value = await getApplicationList()  // 移除异步请求
        // ...
    }
})

onMounted(async () => {
    applicationList.value = await getApplicationList()
})
生命周期执行时机说明
onLoad页面加载时,同步执行formData 会立即被赋值
onMounted组件挂载后执行此时表单已渲染,formData 已有值

原理

  1. onLoad 变成同步执行后,formData 会在表单渲染前被赋值

  2. uView 表单组件在渲染时,model 已经是有效的对象

  3. getApplicationList() 在 onMounted 中异步执行,不影响表单初始化

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐