element中form组件prop嵌套属性的问题解决

目录
  • Introduction
  • 总结

Introduction

分享今天同事问的一个问题, 下面这段代码会报错,先看代码:重点是el-form-item组件的prop属性

<template>
  <div id="app">
    <el-form label-width="100px" :model="ruleForm" :rules="rules">

      <el-form-item
        v-for="(item, index) in tableData"
        :key="item.id"
        :prop="'tableData.' + index + '.name'"
        :rules="rules.name"
      >
        <el-input v-model="item.name"></el-input>
      </el-form-item>

    </el-form>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      ruleForm: {
        name: ''
      },
      tableData: [
        { id: 1, name: "" },
        { id: 2, name: "" },
      ],
      rules: {
        name: [
          {
            required: true,
            message: "请输入活动名称",
            trigger: "blur",
            validator(rule, value, callback) {
              console.log("rule: ", rule);
              console.log("value: ", value);
            },
          },
        ],
      },
    };
  },
};
</script>

我第一眼看上去的时候并没有发现什么问题,但这段代码实实在在的报错了,我们来看一下错误

首先需要明确的是 这是一个警告, 并非一个error, 但他直接导致了我们的代码执行结果非预期,我们来分析一下这个错误

1.首先这个错误的第一句**Error in mounted hook**, 错误发生在mounted钩子中

2.请安排一个有效的path给prop

首先第一个问题,我的代码中并没有mounted函数,他怎么会报错呢?
第二个问题,让我们提供一个有效的prop, 但这里我们明明给的是有效的撒。
最后查了官网并查了百度 都没有找到很好的解决方式,最后没有办法,只能去看一下element-ui的源码, 下面是源码环节:

1.找到packages/form/src/form-item.vue这个文件

2. 我们根据他的报错来分析, 首先他说`mounted hook`中报错, 那我们就直接来看这个hook做了什么事情:

mounted() {
  if (this.prop) {
    this.dispatch('ElForm', 'el.form.addField', [this]); // 这一步不用管

    let initialValue = this.fieldValue; // 取得fieldvalue
    // 判断fieldvalue是不是数组, 如果是数组则合并
    if (Array.isArray(initialValue)) {
      initialValue = [].concat(initialValue);
    }
    // 给this定义一个initialValue属性
    Object.defineProperty(this, 'initialValue', {
      value: initialValue
    });

    this.addValidateEvents();
  }
}

我看这段代码的第一反应是, 这也没干什么事儿啊, 就取了个值 赋了个值, 看了一会儿我发现, 有一个盲点就是this.fieldValue这里, 这是一个什么东西呢?不知道 去看一下。

  computed: {
      fieldValue() {
        // 1.拿到当前"form"的model属性(这里很重要, 要记住这一步)
        const model = this.form.model;
        if (!model || !this.prop) { return; }

        // 2.拿到当前"form-item"的prop属性,
        // 也就是我们传的那个:prop="'tableData.' + index + '.name'"
        let path = this.prop;
        if (path.indexOf(':') !== -1) {
          path = path.replace(/:/, '.');
        }
        // 3.将model和path传给了getPropByPath方法
        return getPropByPath(model, path, true).v;
      }
  }

代码翻到fieldValue这里, 发现这是一个computed属性(步骤见注释), 发现最终返回getPropByPath方法的返回结果, 我们接着去看一下这个方法.
我们发现这个方法是在utils/util下的一个方法

第一眼看到这个方法, 是不是有一种眼熟的感觉?越看越像js的一个面试题

function getValue(obj, path) {
 ...
}

const obj = { a: { b: { c: '1' } } }

getValue(obj, 'a.b.c'); // 1

有木有啊! 有木有!不能说一模一样,只能说分毫不差,既然知道它是面试题就简单了,我们首先需要明确 这个方法的作用就是 通过嵌套字符串key 拿到key对应的value, 那我们来看一下element是怎么做的。

首先先看第一句代码let tempObj = obj, 这里第一次的obj是谁呢?是不是上面传过来的this.form.model啊? 我们来看一下 我们代码中传输的model是什么

我们这里只需要记住, 我们传的是一个对象{ name: '' }好的 我们再来看下一步, path = 正则匹配, 最后的结果是keyArr = ['tableData', 0, 'name']下面的代码就是走keyArr的循环了, 这里我们是3次循环, 因为keyArr只有三个元素

我们还是来捋一下:

1. 第一次循环, 此时的tempObj是 { name: '' }, key是tableData, key in tempObj?, 很显然是false, 所以直接走了else, 触发了throw new Error

其实看到这里我们就明白了, element在做prop判断的时候, 是通过判断key在不在model中的方式 来判断path是否合法的, 那我们知道这个原理之后, 只需要将我们的代码稍稍改动一下即可。

我们只需要将tableData移到ruleForm中即可, 然后我们再来看控制台已经不报错了。

总结

我考虑了一下element为什么要这样做,因为在这样的前提下,只看文档 应该不会得到有用的信息, 后来想了一会儿想通了, 因为element要判断prop传递的值是否合法的话, 就只能用 一个obj 一个key 通过key in obj 这样的方式来判断, 而如果我们不把tableData放到ruleForm中, form-itemmounted的时候 是拿不到外面thisdata的, 所以他无法判断 当前传进来的tableData到底是谁, 也就没有办法使用key in obj.

到此这篇关于element中form组件prop嵌套属性的问题解决的文章就介绍到这了,更多相关element form组件prop嵌套内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • element中el-form-item属性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')" elemen

  • element中form组件prop嵌套属性的问题解决

    目录 Introduction 总结 Introduction 分享今天同事问的一个问题, 下面这段代码会报错,先看代码:重点是el-form-item组件的prop属性 <template> <div id="app"> <el-form label-width="100px" :model="ruleForm" :rules="rules"> <el-form-item v-for

  • Element中table组件按照属性执行合并操作详解

    在实际开发中,要求使用elementUI的table组件对表格数据上下行相邻相同的数据进行合并,在elem官网上查看到是有对应的组件和合并方法 <el-table :data="tableData" :span-method="objectSpanMethod"> <el-table-column prop="id" label="ID" width="180"> </el-t

  • element 中 el-menu 组件的无限极循环思路代码详解

    实现思路主要组件嵌套(组件自己调用自己) 下面是组件所需要的数据 { "code": 1, "data": { "menuVoList": [ { "childList": [ { "childList": [], "menu": { "createBy": "0-1", "createTime": 1587610158, &q

  • 解决Element中el-date-picker组件不回填的情况

    1.问题描述 当我们在实用ElementUI组件完成项目的时候可能会遇到这样的需求,比如: 新建一个活动,需要定义活动的时间范围: 因此我们在新建活动的操作过程中需要选择一段时间区间以及活动名称等信息提交,新建完成: 网页上出现了新建好的活动,其他人想查看详细信息,打开页面,发现时间区间并没有实现回填! 2.问题分析 时间信息没有回填,首先要检查,后台数据返回情况以及页面上字段信息是否有差异等细节: 如果没有以上的情况,那就是我碰到的这种情况了, 后端数据返回没有差异,而且页面字段也没有错,其他

  • js实现Element中input组件的部分功能并封装成组件(实例代码)

    现在实现的有基础用法.可清空.密码框,参考链接:https://element.eleme.cn/#/zh-CN/component/input HTML代码:想要测试哪个组件,直接将对应组件解开注释即可,标红的js和css记得修改成你自己的位置. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>js实现可清空input组件</title> &

  • iOS App开发中UITextField组件的常用属性小结

    重点属性 在 Xcode 中使用 IB 给视图拖上去一个文本框后,选中文本框,可以在Attribute Inspector中设置其各种属性. Attribute Inspector 分为三部分,分别是 Text Field.Control 和 View 部分.我们重点看看 Text Field 部分. Text Field 部分有以下选项: 1.Text :设置文本框的默认文本. 2.Placeholder : 可以在文本框中显示灰色的字,用于提示用户应该在这个文本框输入什么内容.当这个文本框中

  • element组件中自定义组件的样式不生效问题(vue scoped scss无效)

    目录 element组件中自定义组件的样式不生效 解决方法 Element-UI修改样式不影响其他组件 需求描述 方法 element组件中自定义组件的样式不生效 当我们在项目中需要给element组件加上一些自定义样式的时候,往往是不生效的. 这是因为Vue项目中使用第三方框架的时候,Vue中有scoped,声明了样式是在组件范围内生效的,避免了不同组件的样式污染. 解决方法 1. 去掉scoped 这种方法确实可以实现效果,简单粗暴,却会造成不同组件样式污染,不建议. 2. 使用 /deep

  • ASP.NET中Form表单不可以嵌套使用

    我非常确定在ASP 中是可以有多个form 表单的,以前常常这样干的,在后台分类管理页面中,把添加和修改放在同一个页面,这样就需要用到两个 form 表单进行提交服务器代码处理. 经过测试,在ASP.NET 也是可以一个页面有多个form 表单的,例如下面的代码: <form id="form1"></form><form id="form2"></form><form id="form3"&

  • vue中element 的upload组件发送请求给后端操作

    1.用到了before-upload属性, 用于在上传文件前的校验,并且发送请求给后端,传输格式进行文件流传输 什么都不用设置,action属性随便设置,不能为空即可! 在before-upload属性的方法中的代码如下: var _this = this; debugger; // var files=file.target.files[0]; debugger; const isJPG = file.type === "image/jpeg"; const isLt2M = fil

随机推荐