Vue + element-ui实现动态表单项以及动态校验规则

Vue + element-ui实现动态表单项以及动态校验规则

情境

项目需要实现一个功能,表单中某个表单项产品id支持动态新增多个产品id表单项,每个产品id表单项都需要有校验规则,校验失败时各自有对应的校验提示

重点分析

  1. 表单对象内字段并非固定,需要根据交互动态新增
  2. 表单校验规则并非固定,需要根据字段新增动态新增对应校验规则
  3. 接口提交时并非提交多个产品id字段,需要将多个产品id文本字段整合为一个产品id数组字段

实现

核心:表单增加动态多个产品id字段以及产品id数组字段,产品id字段前缀相同,通过后缀序号区分不同字段,实际提交时整合字段为数组字段

1.模板语法

产品id数组字段的长度与产品id字段的个数始终保持一致

html 复制代码
<el-form
    :model="addForm"
    label-suffix=":"
    label-width="120px"
    :rules="rules"
    ref="form"
>
    <el-col :span="12" v-for="(item, index) in addForm.superModelSkuIdList" :key="index">
        <el-form-item :label="formatSkuId(index)" :prop="'skuId' + index">
            <div class="skuId-item">
                <el-input
                    v-model.trim="addForm['skuId' + index]"
                    placeholder="请输入产品id"
                    maxlength="50"
                    style="display: inline-block;"
                >
                </el-input>
                <i
                    style="display: inline-block;"
                    class="el-icon-circle-plus-outline icon"
                    @click="handleAddId"/>
            </div>
        </el-form-item>
    </el-col>
</el-form>

2.核心逻辑

javascript 复制代码
export default {
    data() {
        return {
            addForm: {
                // ...其他字段
                superModelSkuIdList: [''],
            },
        }
    },
    computed: {
        // 表单项动态变化,校验规则也需作为计算属性动态变化
        rules() {
            const checkSkuId = (rule, value, callback) => {
                // 产品id的校验逻辑
            }
            let staticRules = {
                // 其他字段的校验逻辑
            }
            let skuIdRules = {}
            let rule = [
                {
                    validator: checkSkuId,
                    trigger: 'blur',
                },
            ]
            // 为每个产品id字段设置相同的校验逻辑
            this.addForm.superModelSkuIdList.forEach((item, index) => {
                skuIdRules['skuId' + index] = rule
            })
            return Object.assign(staticRules, skuIdRules)
        }
    },
    methods: {
        // 新增产品id
        handleAddId() {
            this.addForm.superModelSkuIdList.push('')
            this.$set(this.addForm, 'skuId' + (this.addForm.superModelSkuIdList.length - 1), '')
        },
        // 根据产品id数组字段生成多个产品id字段
        createSkuIds() {
            // 使用this.$set保证新增对象字段具有响应性
            this.addForm.superModelSkuIdList.forEach((item, index) => {
                this.$set(this.addForm, 'skuId' + index, item)
            })
        },
        // 打开表单编辑弹窗时初始化产品id以及产品id数组字段
        openAddDialog(title, row = {}) {
            // ...其他逻辑
            this.addForm.superModelSkuIdList = [...row.superModelSkuIdList] || ['']
            this.createSkuIds()
        },
        // 需求中提交表单前需要清除产品id为空的项,清空后重新生成非空值的表单项
        clearEmptySkuId() {
            let list = []
            this.addForm.superModelSkuIdList.forEach((item, index) => {
                if(this.addForm['skuId' + index]) list.push(this.addForm['skuId' + index])
                delete this.addForm['skuId' + index]
            })
            this.addForm.superModelSkuIdList = list
            this.createSkuIds()
        },
        // 接口提交时过滤掉所有产品id字段,仅需要产品id数组字段用于提交即可
        deleteSkuIds(skuInfo) {
            this.addForm.superModelSkuIdList.forEach((item, index) => {
                delete skuInfo['skuId' + index]
            })
            return skuInfo
        },
        // 表单提交
        submitForm() {
            this.$refs.form.validate((val) => {
                if (val) {
                    this.clearEmptySkuId()
                    let param = {
                        skuInfo: this.deleteSkuIds({...this.addForm}),
                        // ...其他参数
                    }
                    // ...执行提交相关逻辑
                }
            })
        },
        // 清空还原表单字段,去除产品id字段仅保留产品id数组字段
        resetForm() {
            this.addForm = {
                // ...其他字段
                superModelSkuIdList: [''],
            }
        },
    }
}
相关推荐
赵大仁10 分钟前
深入理解 Vue 3 中的具名插槽
前端·javascript·vue.js·react.js·前端框架·ecmascript·html5
一雨方知深秋15 分钟前
v-bind 操作 class(对象,数组),v-bind 操作 style
前端·css·vue.js·html·style·class·v-bind
安晴晚风1 小时前
从0开始在linux服务器上部署SpringBoot和Vue
linux·运维·前端·数据库·后端·运维开发
前端小小王2 小时前
pnpm、Yarn 和 npm 的区别?
前端·npm·node.js
supermapsupport2 小时前
使用npm包的工程如何引入mapboxgl-enhance/maplibre-gl-enhance扩展包
前端·webpack·npm·supermap·mapboxgl
牛奔2 小时前
windows nvm 切换node版本后,npm找不到
前端·windows·npm·node.js
鱼大大博客2 小时前
Edge SCDN酷盾安全重塑高效安全内容分发新生态
前端·安全·edge
鸭梨山大。2 小时前
NPM组件包 vant部分版本内嵌挖矿代码
前端·安全·npm·node.js·vue
蟾宫曲7 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
秋雨凉人心7 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js