Vue elementUI表单嵌套表格并对每行进行校验详解

目录

效果展示

先看看这是不是需要的效果^_^

Vue elementUI表单嵌套表格并对每行进行校验详解

如图,ElementUI 表单里嵌套了表格,表格内每行能进行【保存】【新增】【编辑】【删除】【重置】等操作,同时可以对每行的某些字段进行校验(而不是整个表单校验!),这种需求很常见,所以记录下来。

代码链接

gitee地址

关键代码

表格数据

// 数据格式必须是【对象嵌套数组】,【form】绑定表单,【list】绑定表格
form: {
  // 表格数据
  list: [
      { id: 1, name: \'小叶\', age: \'12\', phone: \'123456\', show: true },
      { id: 2, name: \'小李\', age: \'23\', phone: \'123457\', show: true },
      { id: 3, name: \'小林\', age: \'12\', phone: \'123458\', show: true }
  ]
},

组件嵌套

  1. 添加字段校验的时候,格式必须写成这样的 :prop="'list.' + scope.$index + '.name'"
    这是 elementui 规定的格式,渲染后的结果为 list.1.name
  2. 每个字段要动态绑定表单的 rules 属性
  3. 如果不是以上的格式,会出错!!!
// 表单必须嵌套在表格的外面,表单必须绑定【rules】【ref】属性
<el-form :model=\"form\" :rules=\"rules\" ref=\"form\">
   <el-table :data=\"form.list\">
       <el-table-column prop=\"name\" label=\"姓名\">
           <template scope=\"scope\">
              // 每个字段动态的绑定表单的【prop】【rules】属性
              <el-form-item :prop=\"\'list.\' + scope.$index + \'.name\'\"                                              :rules=\"rules.name\">
                    <el-input size=\"mini\" v-model=\"scope.row.name\" placeholder=\"请输入\"                             clearable></el-input>
               </el-form-item>
           </template>
       </el-table-column>
  </el-table>
</el-form>

校验方法

  1. 表单的字段对象存在于 this.$refs['form'].fields 中,并且字段对象具有 prop【datas.1.name】 属性和 validateField 方法【验证 datas.1.name 能否通过校验】
  2. 但是 validateField 方法需要手动创建来验证能否通过校验
  3. 必须创建,否则会出错!!!
// 表单校验方法
// 【form】是需要校验的表单,就是表单中【ref】绑定的字段
// 【index】是需要传入的行数,字段【scope.$index】
validateField(form, index) {
     let result = true;
     for (let item of this.$refs[form].fields) {
         if(item.prop.split(\".\")[1] == index){
             this.$refs[form].validateField(item.prop, err => {
                 if(err !=\"\") {
                     result = false;
                 }
             });
         }
         if(!result) break;
     }
     return result;
}

重置方法

// 对【需要校验】的表单字段进行重置
// 参数同校验方法,如果是全部重置
reset(form, index) {
    this.$refs[form].fields.forEach(item => {
        if(item.prop.split(\".\")[1] == index){
            item.resetField();
        }
    })
}
// 如果需要全部重置可以直接质控表单中字段
// 【row】是每行传入的数据
resetRow(row) {
    row.name = \"\";
    row.age = \"\";
    row.phone = \"\";
}

完整代码

因为用的是在线链接,网络不稳定时页面不一定能加载出来,使用时可以更换成本地的!

<!DOCTYPE html>
<html lang=\"zh\">

<head>
    <meta charset=\"UTF-8\">
    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
    <title>vue表单嵌套表格逐行验证</title>
    <script src=\"https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js\"></script>
    <!-- 引入样式 -->
    <link rel=\"stylesheet\" href=\"https://unpkg.com/element-ui/lib/theme-chalk/index.css\" rel=\"external nofollow\" >
    <!-- 引入组件库 -->
    <script src=\"https://unpkg.com/element-ui/lib/index.js\"></script>
</head>

<body>
    <div id=\"app\">
        <!-- 页面组件 -->
        <h2 style=\"text-align: center; line-height: 23px;color: #909399;\">vue表单嵌套表格逐行验证</h2>
        <el-form :model=\"form\" :rules=\"rules\" ref=\"form\" :inline=\"true\"
            style=\"margin: 23px auto 0px; width: 96%; overflow: hidden;\">
            <el-table border :data=\"form.list\">
                <el-table-column align=\"center\" prop=\"id\" label=\"序号\" width=\"55\">
                </el-table-column>
                <el-table-column align=\"center\" prop=\"name\" label=\"姓名\">
                    <template scope=\"scope\">
                        <el-form-item :prop=\"\'list.\' + scope.$index + \'.name\'\" :rules=\"rules.name\"
                            v-if=\"scope.row.show\">
                            <el-input size=\"mini\" v-model=\"scope.row.name\" placeholder=\"请输入\" clearable>
                            </el-input>
                        </el-form-item>
                        <div v-if=\"!scope.row.show\">{{scope.row.name}}</div>
                    </template>
                </el-table-column>
                <el-table-column align=\"center\" prop=\"age\" label=\"年龄\">
                    <template scope=\"scope\">
                        <el-form-item :prop=\"\'list.\' + scope.$index + \'.age\'\" :rules=\"rules.age\" v-if=\"scope.row.show\">
                            <el-input size=\"mini\" v-model=\"scope.row.age\" placeholder=\"请输入\" clearable>
                            </el-input>
                        </el-form-item>
                        <div v-if=\"!scope.row.show\">{{scope.row.age}}</div>
                    </template>
                </el-table-column>
                <el-table-column align=\"center\" prop=\"phone\" label=\"联系方式\">
                    <template scope=\"scope\">
                        <el-form-item :prop=\"\'list.\' + scope.$index + \'.phone\'\" :rules=\"rules.phone\"
                            v-if=\"scope.row.show\">
                            <!-- <el-form-item v-if=\"scope.row.show\"> -->
                            <el-input size=\"mini\" v-model=\"scope.row.phone\" placeholder=\"请输入\" clearable>
                            </el-input>
                        </el-form-item>
                        <div v-if=\"!scope.row.show\">{{scope.row.phone}}</div>
                    </template>
                </el-table-column>
                <el-table-column label=\"操作\" align=\"center\" width=\"290\" fixed=\"right\">
                    <template slot-scope=\"scope\">
                        <el-button type=\"text\" style=\"color: #E6A23C;\" @click=\"save(scope.$index, scope.row)\"
                            v-if=\"scope.row.show\" icon=\"el-icon-check\">保存
                        </el-button>
                        <el-button type=\"text\" style=\"color: #409EFF;\" @click=\"edit(scope.row)\" v-if=\"!scope.row.show\"
                            icon=\"el-icon-edit\">编辑
                        </el-button>
                        <el-button type=\"text\" style=\"color: #67C23A;\" v-if=\"scope.$index+1 == listLength\"
                            @click=\"addRow(scope.$index, scope.row)\" icon=\"el-icon-plus\">新增
                        </el-button>
                        <el-button type=\"text\" style=\"color: #F56C6C;\" @click=\"delRow(scope.$index, scope.row)\"
                            icon=\"el-icon-delete\">删除
                        </el-button>
                        <el-button type=\"text\" style=\"color: #909399;\" @click=\"reset(\'form\', scope.$index)\"
                            v-if=\"scope.row.show\" icon=\"el-icon-refresh\">重置
                        </el-button>
                        <!-- <el-button type=\"text\" style=\"color: #909399;\" @click=\"resetRow(scope.row)\"
                            v-if=\"scope.row.show\" icon=\"el-icon-refresh\">重置
                        </el-button> -->
                    </template>
                </el-table-column>
            </el-table>
        </el-form>
    </div>
</body>

</html>
<script>
    var app = new Vue({
        el: \'#app\',
        data() {
            return {
                // 表单数据
                form: {
                    // 表格数据
                    list: [{ id: 1, name: \'\', age: \'\', phone: \'\', show: true }]
                },
                // 表单验证规则
                rules: {
                    name: [{ required: true, message: \'请输入姓名!\', trigger: \'blur\' }],
                    age: [{ required: true, message: \'请输入年龄!\', trigger: \'blur\' }],
                    phone: [{ required: true, message: \'请输入联系方式!\', trigger: \'blur\' }],
                },
                // 表格长度默认为 1
                listLength: 1,
            }
        },

        methods: {
            // 校验
            validateField(form, index) {
                let result = true;
                for (let item of this.$refs[form].fields) {
                    if (item.prop.split(\".\")[1] == index) {
                        this.$refs[form].validateField(item.prop, err => {
                            if (err != \"\") {
                                result = false;
                            }
                        });
                    }
                    if (!result) break;
                }
                return result;
            },

            // 重置【只针对校验字段】
            reset(form, index) {
                this.$refs[form].fields.forEach(item => {
                    if (item.prop.split(\".\")[1] == index) {
                        item.resetField();
                    }
                })
            },

            // 重置【全部】
            resetRow(row) {
                row.name = \"\";
                row.age = \"\";
                row.phone = \"\";
            },

            // 保存
            save(index, row) {
                if (!this.validateField(\'form\', index)) return;
                row.show = false;
            },

            // 新增
            addRow(index, row) {
                if (!this.validateField(\'form\', index)) return;
                this.form.list.push({
                    id: index + 2,
                    name: \'\',
                    age: \'\',
                    phone: \'\',
                    show: true
                });
                this.listLength = this.form.list.length;
            },

            // 编辑
            edit(row) {
                row.show = true;
            },

            // 删除
            delRow(index, row) {
                if (this.form.list.length > 1) {
                    this.form.list.splice(index, 1);
                    this.listLength = this.form.list.length;
                } else {
                    this.form.list = [{
                        id: 1,
                        name: \'\',
                        age: \'\',
                        phone: \'\',
                        show: true
                    }];
                }
            },
        }
    })
</script>

总结

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容