uniapp + uview 实现动态表单及校验

3,290 阅读2分钟

使用uniapp+uview开发微信小程序,需求中要涉及到常规表单+API返回的动态表单,并对表单添加验证规则。在实现过程中遇到视图中动态表单数据不即时显示,错误提示不即时消除等问题。就此次踩坑做个记录,便于遇到同样问题的小伙伴。

构建表单数据、验证规则

尝试过在data()中直接写完表单验证规则,然后在应用到<u--from>中,发现校验规则未生效,于是就计划与构建动态表单数据时,一并构建验证规则。

data(){
    info: {
        exFields: [],
    },
    formData: {
        name: "",
        extra: {}
    },
    errorType: 'message',
    fileList: {}, // 图片组件上传图片后预览上传
},
methods: {
    async handleActivityInfo(id){
        try {
                const res = 后端请求返回

                this.info.exFields = res.extra_fields
                this.handleExFields(this.info.exFields)
        } catch(error) {
                console.log(error)
        }
    },
    handleExFields(fields){
    // 此处动态字段的构建,根据后端接收数据的形式进行调整
        fields.forEach(item => {
            this.formData.extra[`extra_${item.id}`] = null
            this.fileList[`extra_${item.id}`] = []
        })

        this.handleRules()
    },
    handleRules() {
        // 非动态字段部分的验证规则
        const rules = {
            'name': {
                type: "string",
                required: true,
                message: "请输入真实姓名",
                trigger: ["blur", "change"]
            },
        }
        
        // 基于动态字段,构建动态字段的验证规则
        this.info.exFields.forEach(item => {
            Object.assign(rules, {
                [`extra.extra_${item.id}`]: {
                    type: item.field_type === 1 ? 'string' : 'string',
                    required: true,
                    message: item.field_type === 1 ? `请输入${item.field_name}` : `请上传${item.field_name}`,
                    trigger: ['blur', 'change'],
                }
            })
        });
    }
    
    this.rules = rules
    this.show = true
    // 表单绑定验证规则
    this.$refs.uForm.setRules(this.rules)
}

视图部分

v-if="show",想着是数据未准备好时,不展示视图,避免提前渲染后相关规则不生效。

<view v-if="show">
<u--form ref="uForm" :model="formData" :rules="rules" labelPosition="top" :errorType="errorType">
    <view class="item">
        <u-form-item label="姓名" prop="name">
            <u--input v-model="formData.name" placeholder="请输入真实姓名"></u--input>
        </u-form-item>
    </view>
    
    <view v-for="(item, index) in info.exFields" :key="item.id">
        <view class="item" v-if="item.field_type == 1">
            <u-form-item :label="item.field_name" :prop="`extra.extra_${item.id}`">
                <u--input
                    v-model="formData.extra[`extra_${item.id}`]"
                    :placeholder="`请输入${item.field_name}`"
                    @blur="(e) => handleValidateField(e,item.id)"
                ></u--input>
            </u-form-item>
        </view>
        <view class="item" v-else>
            <u-form-item :label="item.field_name" :prop="`extra.extra_${item.id}`">
                <u-upload
                    :fileList="fileList[`extra_${item.id}`]"
                    accept="image"
                    @afterRead="(e) => handleAfterRead(e,item.id)"
                    @delete="(e) => handleDeletePic(e, item.id)"
                    :name="`photo_${index}`"
                    imageMode="widthFix"
                    :maxCount="1"
                ></u-upload>
            </u-form-item>
        </view>
</view>
</u--form>
</view>

数据校验

按照前面两部分处理后,能进行数据校验,但是也带来两个问题: 1、视图数据不及时更新,代码console.log却能看到最新的数据; 2、错误提示不自动消失;

处理方式: 表单的验证规则是异步的,所以采用异步的方式进行数据的校验。然后再使用this.$forceUpdate()进行视图数据刷新

async handleValidateField(e,index) {
    try{
        await this.$refs.uForm.validateField(`extra.extra_${index}`)
        this.$refs.uForm.clearValidate(`extra.extra_${index}`)
        this.$forceUpdate()
    } catch(error) {
        console.log(error)
    }
},
async handleAfterRead(e, index){
    const { file } = e
    this.fileRule.folderName = `${this.fileRule.folderName}/${this.info.id}`

    uploadCos(file, this.fileRule.folderName, async res => {
        if(res) {
            const {name, url, location} = res
            this.formData.extra[`extra_${index}`] = location
            
            // 预览图片
            this.fileList[`extra_${index}`] = [{url: `https://${location}`}]

            try {
                await this.$refs.uForm.validateField(`extra.extra_${index}`)
                this.$refs.uForm.clearValidate(`extra.extra_${index}`)
                this.$forceUpdate()
            } catch (error) {
                console.log(error)
            }
        }
    })
},

以上为动态表单数据校验、数据不及时更新的一种处理方式。各位大佬有更好的方式,还请指导指导。