zoukankan      html  css  js  c++  java
  • element中elformitem属性prop踩坑

    最近负责前后端项目开发,有个需求是实现Djangorestframework(drf)+element实现动态渲染form表单,drf后端提供json,前端从json中获取form表单元素,并且绑定表单验证规则
    在el-form-item属性prop上遇到报错或者没绑定到数据,报错如下
    [Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'prop')"
    element官方文档解释el-form-item的prop必须是el-form属性model的直接子属性
    后端返回数据如下

    {
        "status": "success",
        "code": 200,
        "data": {
            "form_attributes": {
                "inline": true,
                "label-width": "auto",
                "size": "small"
            },
            "form_data": {
                "name": null,
                "path": null,
                "component": null,
                "hidden": false,
                "meta": {
                    "icon": null,
                    "title": null
                },
                "pid": null
            },
            "form_item_list": [
                {
                    "type": "text",
                    "prop": "name",
                    "label": "菜单名",
                    "placeholder": "请输入菜单名",
                    "rules": [
                        {
                            "required": true,
                            "message": "请输入菜单名",
                            "trigger": "blur"
                        }
                    ]
                },
                {
                    "type": "text",
                    "prop": "path",
                    "label": "链接地址",
                    "placeholder": "'/'开头",
                    "rules": [
                        {
                            "required": true,
                            "message": "'/'开头",
                            "trigger": "blur"
                        }
                    ]
                },
                {
                    "type": "text",
                    "prop": "component",
                    "label": "组件",
                    "placeholder": "参考前端组件填写",
                    "rules": [
                        {
                            "required": true,
                            "message": "参考前端组件填写",
                            "trigger": "blur"
                        }
                    ]
                },
                {
                    "type": "switch",
                    "prop": "hidden",
                    "label": "是否隐藏",
                    "value": false
                },
                {
                    "type": "json",
                    "prop": "meta",
                    "item": [
                        {
                            "type": "text",
                            "prop": "icon",
                            "label": "图标",
                            "placeholder": "图标名字,参考前端图标",
                            "rules": [
                                {
                                    "required": true,
                                    "message": "图标名字,参考前端图标",
                                    "trigger": "blur"
                                }
                            ]
                        },
                        {
                            "type": "text",
                            "prop": "title",
                            "label": "标题",
                            "placeholder": "请输入菜单名",
                            "rules": [
                                {
                                    "required": true,
                                    "message": "请输入菜单名",
                                    "trigger": "blur"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "select",
                    "prop": "pid",
                    "label": "父菜单",
                    "clearable": true,
                    "filterable": false,
                    "multiple": false,
                    "options": [
                        {
                            "label": "系统管理",
                            "value": 2
                        },
                        {
                            "label": "用户管理",
                            "value": 3
                        },
                        {
                            "label": "菜单管理",
                            "value": 4
                        },
                        {
                            "label": "权限管理",
                            "value": 5
                        },
                        {
                            "label": "角色管理",
                            "value": 6
                        }
                    ]
                }
            ]
        },
        "message": null
    }
    

    从上面可以看到form表单元素对应的是 form_item_list,表单提交数据是 form_data,这两个是分开,也就是el-form中model绑定是 form_data 而el-form-item遍历的是 form_item_list,注意 form_item_list 中含有嵌套类型json,对应的后端是json字段渲染表单,单独提供form_data返回字段设计是为了控制前端json内容,动态字段中过于灵活,可以随意修改json包含的字段和类型,所以返回字段由后端控制和校验

    截取前端渲染表单代码如下,注意这个时候能渲染但是rules绑定是失败的

    <!-- 添加菜单对话框 -->
        <el-dialog title="添加菜单" :visible.sync="addDialogVisible" width="50%" :close-on-click-modal="false" @close="addDialogClosed">
    
          <!-- 表单内容主体 -->
          <el-form ref="addFormRef" :model="formData" :size="formAttributes.size" :inline="formAttributes.inline" :label-width="formAttributes.labelWidth">
            <div v-for="(item, index) in formItemList" :key="index">
              <el-form-item :prop="formItemList + index + item.prop" :label="item.label" :rules="item.rules">
                <!-- text输入框 -->
                <el-input v-if="item.type==='text'" v-model="formData[item.prop]" clearable :placeholder="item.placeholder"></el-input>
                <!-- textarea输入框 -->
                <el-input v-if="item.type==='textarea'" v-model="formData[item.prop]" clearable autosize :type="textarea" :placeholder="item.placeholder"></el-input>
                <!-- 下拉框 -->
                <el-select v-if="item.type==='select'" v-model="formData[item.prop]" clearable :multiple="item.multiple">
                  <el-option v-for="op in item.options" :key="op.value" :label="op.label" :value="op.value"></el-option>
                </el-select>
                <el-switch v-if="item.type==='switch'" v-model="formData[item.prop]" :label="item.label"></el-switch>
    
                <template v-if="item.type==='json'">
                  <div v-for="(json_item, json_index) in item.item" :key="json_index">
                    <el-form-item :prop="item.item + json_index + json_item.prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;">
                      <!-- text输入框 -->
                      <el-input v-if="json_item.type==='text'" v-model="formData[item.prop][json_item.prop]" clearable :placeholder="json_item.placeholder"></el-input>
                      <!-- textarea输入框 -->
                      <el-input v-if="json_item.type==='textarea'" v-model="formData[json_item.prop]" clearable autosize :type="textarea" :placeholder="json_item.placeholder"></el-input>
                      <!-- 下拉框 -->
                      <!-- <el-select v-if="item.type==='select'" v-model="formData[item.prop]" clearable :placeholder="item.label" :multiple="item.multiple" @change="item.change(formData[item.prop])"> -->
                      <el-select v-if="json_item.type==='select'" v-model="formData[json_item.prop]" clearable :multiple="json_item.multiple">
                        <el-option v-for="op in json_item.options" :key="op.value" :label="op.label" :value="op.value"></el-option>
                      </el-select>
                      <el-switch v-if="json_item.type==='switch'" v-model="formData[json_item.prop]" :label="json_item.label"></el-switch>
                    </el-form-item>
                  </div>
                </template>
    
              </el-form-item>
            </div>
          </el-form>
    
          <!-- 底部 -->
          <el-divider></el-divider>
          <span slot="footer" class="dialog-footer">
            <el-button @click="addDialogVisible = false">取消</el-button>
            <el-button type="primary" @click="addForm">确定</el-button>
          </span>
        </el-dialog>
    

    在前端渲染无法绑定到表单规则,如下图

    经过研究,从上面的数据结构可以发现,form_data 中每个元素对应是 form_item_list 中的 prop,那么有两个写法可以定位
    第一种写法如下,这种写法没那么直观

    <!-- 普通字段渲染 -->
    <el-form-item :prop="item.prop" :label="item.label" :rules="item.rules">
    <!-- json字段渲染 -->
    <el-form-item :prop="item.prop + '.' + json_item.prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;">
    

    更好的第二种写法如下

    <el-form-item :prop="formItemList[index].prop" :label="item.label" :rules="item.rules">
    <el-form-item :prop="formItemList[index].prop + '.' + item.item[json_index].prop" :label="json_item.label" :rules="json_item.rules" style="margin-left: -80px;">
    

    此时能动态渲染表单和绑定表单项验证规则,如下图

    总结:上面两种写法都是为了定位到表单元素对应的表单的model直接子属性,踩坑的原因是遍历表单的列表(v-for)和表单提交数据(model)不是在一个对象下,尤其是遍历表单下,还包括嵌套表单json处理,需要注意定位json提交数据

  • 相关阅读:
    今天开始用 VSU 2010
    Visual Studio 2010 模型设计工具 基本应用
    Asp.Net访问Oracle 数据库 执行SQL语句和调用存储过程
    Enterprise Library 4.1 Security Block 快速使用图文笔记
    解决“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本。”(图)
    一个Oracle存储过程示例
    Enterprise Library 4.1 Application Settings 快速使用图文笔记
    Oracle 10g for Windows 简体中文版的安装过程
    Oracle 11g for Windows 简体中文版的安装过程
    Oracle 9i 数据库 创建数据库 Net 配置 创建表 SQL查询 创建存储过程 (图)
  • 原文地址:https://www.cnblogs.com/AutoSmart/p/15757085.html
Copyright © 2011-2022 走看看