针对复杂自定义组件的表单验证不理想,希望能得到改善建议

qngyun1029
  • 742

先上图再说明,如下:
val.png

看上去比较交单的一个表单,使用elementui实现,表单中三个字段分别对应:

formData: {
    name: '',
    depts: [], //部门
    deptsGroups: [[]], //部门组
},

字段及验证标准如下:
name: 普通输入框(不能为空);
depts: 为自定义的部门选择器组件depSelector(不能为空);
deptsGroups: 为自定义的部门组组件depGroup(组不能为空,且每组部门也不能为空);

问题如下:
1、部门字段,当选择部门合法时,部门错误验证提示没有消除,需要点击立即创建来验证表单,错误消息才会清楚;(目前办法是在部门组件事件监听里面赋值后验证一下该字段就可以了,虽然麻烦,但是可以解决掉这个问题)
2、部门组没有显示表示必填的红色星号(手动添加,虽然麻烦);
3、部门组组件提示不够友好,第一组选择了“部门4”,但是红色框仍没有清除;我希望有两种方式二选一都可以:

  • 局部提示:合法的已选择“部门4”组,不提示错误信息;未选择的第二组第三组每组下面显示提示文字当前组不能为空
  • 整体提示:就是把部门组对应的组件当一个整体对待,每组不局部提示错误信息(不管是否合法的组都不显示红色框),整体错误提示如上图在最下面显示各部门组中部门不能为空,如果可以在整个3组最外面套一个红色大框更好,就好比普通的输入框的错误提示一样;(把depSelector组件的input框改为div模拟,可以做到每组不提示,只显示整体错误,但是整体外面没有红色框——不过这和自带的checkbox验证一样)

代码如下:

index.vue

<template>
    <div style="padding: 40px;">
        <div style="margin-bottom: 20px;">
            输出表单内容:{{ formData }}
        </div>
        <el-form ref="form" :model="formData" :rules="rules" label-width="80px">
            <el-form-item label="名称" prop="name">
                <el-input v-model="formData.name"></el-input>
            </el-form-item>
            <el-form-item label="部门" prop="depts">
                <dep-selector @changed='handleChanged'></dep-selector>
            </el-form-item>
            <el-form-item label="部门组" prop="deptsGroups">
                <dep-group @groupChanged='handleGroupChanged'></dep-group>
                <input type="hidden" v-model="deptsGroups">
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="onSubmit">立即创建</el-button>
                <el-button>取消</el-button>
            </el-form-item>
        </el-form>
    </div>
</template>

<script>
import depSelector from './depSelector'
import depGroup from './depGroup'
export default {
    name: 'custom-component-validate',
    components: {
        depSelector,
        depGroup,
    },
    data() {
        //项目组不能为空,且每组选择的部门不能为空
        var checkDeptGroups = (rule, value, callback) => {
            if (!value || value.length == 0) { //必须添加部门组
                return callback(new Error('必须添加部门组集合'));
            }
            if(value.findIndex(s => s.length == 0) > -1) { //部门组中,每个部门都不能为空
                callback(new Error('各部门组中部门不能为空'))
            } else {
                callback()
            }
        };

        return {
            formData: {
                name: '',
                depts: [], //部门
                deptsGroups: [[]], //部门组
            },
            rules: {
                name: [
                    { required: true, message: '请输入name', trigger: 'change' },
                ],
                depts: [
                    { required: true, message: '请选择部门', trigger: 'change' }
                ],
                deptsGroups: [
                    {
                        validator: checkDeptGroups, trigger: 'change'
                    }
                ]
            }
        }
    },
    methods: {
        onSubmit(){
            this.$refs.form.validate((valid) => {
                if (valid) {
                    alert('submit!');
                } else {
                    console.log('error submit!!');
                    return false;
                }
            })
        },
        handleChanged(depts) {
            this.formData.depts = depts
        },
        handleGroupChanged(groups) {
            this.formData.deptsGroups = groups
        }
    },
}
</script>

depSelector.vue

<template>
    <div>
        <el-input :value="deptStr" readonly="readonly" placeholder="">
            <template slot="append">
                <el-button type="text" @click="dialogVisible = true"> 选择部门 </el-button>
            </template>
        </el-input>
        <el-dialog
            title="请选择部门"
            :visible.sync="dialogVisible"
            width="500px"
            :before-close="() => dialogVisible = false"
        >
            <el-checkbox-group v-model="list">
                <el-checkbox v-for="d in depts" :key="d.deptId" :label="d.deptId">{{d.deptName}}</el-checkbox>
            </el-checkbox-group>
            <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="handleSave">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
export default {
    name: 'dep-selector',
    props: {
        selected: {
            type: Array,
            default: () => {
                return []
            }
        },
    },
    computed: {
        deptStr() {
            return this.depts.filter(s => this.list.findIndex(d => d == s.deptId) > -1).map(s => s.deptName).join(',')
        }
    },
    data() {
        return {
            dialogVisible: false,
            list: JSON.parse(JSON.stringify(this.selected)),

            depts: [
                {deptId: 1, deptName: '部门111'},
                {deptId: 2, deptName: '部门2'},
                {deptId: 3, deptName: '部门3'},
                {deptId: 4, deptName: '部门4'},
                {deptId: 5, deptName: '部门5'},
            ]
        }
    },
    methods: {
        handleSave() {
            this.dialogVisible = false
            this.$emit('changed', this.list)
        },
    },
}
</script>

depGroup.vue

<template>
    <div>
        <div>
            <el-button type="text" @click="handleAdd">新增部门组</el-button>
        </div>
        <div style="padding-bottom: 12px;" v-for="(g, idx) in groups" :key="idx">
            <dep-selector :key="idx" @changed='handleChanged($event, idx)'></dep-selector>
        </div>
    </div>
</template>

<script>
import depSelector from './depSelector'
export default {
    name: 'dep-group',
    components: {
        depSelector,
    },
    data() {
        return {
            groups: [[]]
        }
    },
    methods: {
        handleAdd() {
            this.groups.push([])
            this.$emit('groupChanged', this.groups)
        },
        handleChanged(deps, idx) {
            this.groups.splice(idx, 1, deps)
            this.$emit('groupChanged', this.groups)
        },
    }
}
</script>
回复
阅读 463
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏