form中el-table数据不显示_el-form-renderer 1.14.0 版本重磅发布:支持 v-model(硬核解读)

c6201440b617a949eac87faa1ed096df.png

前言

此时更新主要带来了 v-model 功能,并加入了 cypress 做 e2e 测试来护航。下面一起来回顾一下开发小哥此次版本迭代的精彩历程吧~

目标:v-model

功能:v-model

这次 feature 版本更新,主要是为了 v-model 功能开展的。其可以解决以下问题:

  • 不再需要对 ref 操作 updateForm、getFormValue 来与数据交互
  • 可以直接观察当前的表单数据变更,来进行特定操作

后续对 valid 状态,也通过 prop + sync 的形式管理,基本就可以脱离对 ref 的依赖。

提升代码质量

由于 el-form-renderer 已经是历时两年多的开源项目,许多代码经多人转手,已经存在以下问题:

  • 不合适的写法。比如大量使用 render 函数;
  • 大量使用 mixin 和字符串拼接来调用功能,开发者难以定位调用链条。比如在生成 option 数组时;
  • 废弃的功能。比如不太好用的 enableWhen 等等
  • 没有注释的 hack。比如尝试兼容 select, radio & checkbox 用法的代码(在1.14.1版本修复)

所以提高维护性也是本次迭代的重中之重。

下面就开始着手开发。

♻️ 测试

https://github.com/FEMessage/el-form-renderer/pull/159​github.com

第一步,就是加入自动化测试。

先前,项目中已经引入了 jest 做单元测试。单元测试可以保证一些核心逻辑的稳定性,比如一些数据处理、转换函数的输入输出意图。但是其没有办法测试真实示例使用起来时的稳定性,比如用户真正在表单中输入值、点击重置按钮的行为。此前,行为的稳定性只能依赖开发者和 review 人员手动对示例进行测试。

现在,项目使用 cypress 来对每个示例的行为进行自动化测试。这样开发者可以放心重构和添加功能,同时轻松维护过往表现的一致性。

如何写行为测试

重点应当关注用户行为层面,而不是代码输出层面。比如,应当测试:

  1. 用户输入文本
  2. 确认文本框中有该内容
  3. 用户点击提交按钮
  4. 确认窗口内显示成功信息

而不是:

  1. 用户点击按钮
  2. 等待某个接口有返回内容(这测试的是按钮有没绑定到函数,和接口是否正常

重构

https://github.com/FEMessage/el-form-renderer/pull/161​github.com

重构的主要成果是:

  1. 用 template 重构了所以 render 函数。代码更符合 Vue 规范写法
  2. 移除了 mixin。将相关功能转化成纯函数,并补充单元测试用例
  3. 层级调整。vue 组件移到 components 目录下;js 文件移到 util 目录下
  4. 优化函数命名。比如使用具体的 removeDollarInKey 替代 transformItem
  5. 梳理了关键复杂点的逻辑,并提取成纯函数,补充单元测试。包括:
  6. transformInputFormat(用 inputFormat 处理初始和 updateForm 的值)
  7. transformOutputFormat(用 outputFormat 处理 getFormValue 的值)
  8. collect(从 content 中搜集 options 和初始 value)
  9. 补全了所有关键示例的端测试

inputFormat & outputFormat

这次重构的最大难点,就是处理 inputFormat、 outputFormat、group 与表单值 value 的逻辑。直接给出定义的话:

  • 每个表单项的 inputFormat 接受当前 这一层(group) 的值,返回 当前项的值
  • 每个表单项的 outputFormat 接受 当前项的值 ,返回的值先判断是不是对象:
  • 如果不是,返回值视作 当前项的值
  • 如果是,返回值将整体覆盖到 这一层(group) 的值

具体看如下示例。使用到的同学请务必注意其用法

inputFormat

作者之前以为

// content 配置
{
  id: 'a',
  inputFormat: v => v + 1 // 接受传入值,返回新值
}
//
this.$refs.form.updateForm({a: 1})
this.$refs.form.getFormValue() // {a: 2}

实际上

// content 配置
{
  id: 'a',
  inputFormat: formValue => formValue.notA // 接受整个 formValue 来处理!
}
//
this.$refs.form.updateForm({notA: 1})
this.$refs.form.getFormValue() // {a: 1}

outputFormat

作者之前以为

// content 配置
[
  {
    id: 'a',
    default: 1,
    outputFormat: a => a + 1 // 接受内部值,返回处理过的值
  },
  {
    id: 'b',
    default: {c: 2},
    outputFormat: b => (b.c += 1, b)
  },
]
//
this.$refs.form.getFormValue() // {a: 2, b: {c: 3}}

实际上

// content 配置
[
  {
    id: 'a',
    default: 1,
    outputFormat: a => a + 1 // 这个的理解是对的
  },
  {
    id: 'b',
    default: {c: 2},
    outputFormat: b => (b.c += 1, b) // 当返回值是对象时,会整体覆盖到上一层!
  },
]
//
this.$refs.form.getFormValue() // {a: 2, c: 3}

✨ 开发功能:v-model

https://github.com/FEMessage/el-form-renderer/pull/162​github.com

开发过程一度顺风顺水:

  1. 新增属性 form,作为对外 v-model 的属性
  2. 在 watch 里对接数据流水线:
  3. 监听 form、content 的变更 -> 搜集初始值 --inputFormat--> value
  4. 监听 value 的变更 --outputFormat--> form
  5. 写新的示例 v-model.md 和测试 v-model.spec.js(参考 basic 即可)

这时 cypress 报告了一个 诡异的现象

有 bug ?

先简单说一下测试用例流程:

  1. 输入各种 input、select、radio
  2. 检查输入后 v-model 的状态
  3. 点击 reset 按钮,v-model 回到初始状态

诡异情况发生了:

  1. 在模拟点击 reset 按钮时,发现 cypress 测试里点击重置按钮, reset 未生效?
  2. 作者 手动在 cypress 的调试浏览器中点击按钮,reset 生效了!
  3. 在 reset 函数里打点,发现 reset 函数在以上情况中 都有被正常调用
  4. 尝试在 cypress 代码中 先等待 1秒再点击按钮,reset 未生效
  5. 尝试在 cypress 代码中 连续写两次 click 按钮操作,reset 又生效了!
是 cypress 的问题?不管了直接在测试用例里写注释吧,就说明手动测试是 ok 的,连点两次是 hack 写法。 —— 我脑海里有个声音飘过。

好在作者冷静了点,利用这个契机好好地 review 了下原本的 resetFields 逻辑,发现了如下问题:

  • reset 后 el-select 报错的 bug
  • reset 后,value 监听器监听不到改变,因为 el-form 的实现机制中改了 value 后没有 emit input 事件
  • 如果在监听器上加 deep: true,则会发现新值和旧值居然是一样的。原因暂时不明

在发现以上问题基础上,我对代码进行如下修改:

  • 在 form、value 监听器中用 lodash 的 isequal 判断前后的值,有变更时才 emit input 事件
  • 参考 el-form 机制在内部实现了 resetFields:用的是 mounted 时传入的值,然后清除校验错误信息

现在用例一切正常了,诡异情况也没有再出现。虽然到头来我仍没有弄清楚 为什么 cypress 的模拟操作代码调用的 resetFields 没有正常运作 ,但其恰好提醒了我此时有异常表现,我才发现了 resetFields 的其他问题。重视测试 的行为让组件得到了回报。

关于初始状态

值得一提的是,目前 resetFields 所认定的 初始状态,是在组件 mounted 阶段时 v-model 的值。这点与 element 一致,因为一些 element 表单组件,会在 created 阶段,在传入的 value 值不合法时会重新 emit 一个正确的初始值给到 v-model。比如:

  • 开启了 multiple 的 el-select,会修正初始值为 []
  • el-checkbox,会修正初始值为 []由 el-form-renderer 实现,原生是没有的哦)

更新文档

https://github.com/FEMessage/el-form-renderer/pull/163​github.com

此次更新顺带修复了一些老示例的错误用法。可能不少 el-form-renderer 的用户还不了解,el-form-renderer 的 disabled 属性,统一在配置最上层级设置:

// content 定义
[
  {
    disabled: true, // 在这里设置
    el: {
      disabled: true // 无效
    }
  }
]

意外之喜

Femessage El Form Renderer Style Guide​femessage.github.io

在写 v-model 数据流水线时,因为把 content 也融入在其中,所以现在可以在运行时修改 content,并观测表单变化了!

结语

el-form-renderer 虽然一路遭遇到吐槽很多,但更多的是忠实粉丝们孜孜不倦地为其提交代码。直到今天,可以看到其相对于原生 element,开发体验已经有了长足的进步。现在有了端对端测试,开发和维护功能更是如虎添翼。这里感谢已为开源作出贡献的开发者们,也欢迎更多小伙伴加入我们 deepexi 开源生态中哦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
el-form-renderer是一个基于Element UI的表单渲染器,用于简化表单的开发和校验。而el-form-item是el-form-renderer的一个组件,用于包裹表单项并进行校验。 在el-form-item,可以通过rules属性来定义校验规则。rules属性是一个数组,每个元素都是一个对象,用于描述一个校验规则。每个规则对象包含以下属性: 1. required(必填):指定该字段是否为必填项,可以是一个布尔或者一个函数。如果是函数,则根据函数的返回来确定是否必填。 2. validator(自定义校验函数):指定一个自定义的校验函数,该函数接收三个参数:rule(当前规则对象)、value(当前字段)和callback(回调函数)。在自定义校验函数,可以根据具体的业务逻辑进行校验,并通过调用callback回调函数来返回校验结果。 3. trigger(触发方式):指定触发校验的方式,默认为'change',即在字段改变时触发校验。还可以设置为'blur'(失去焦点时触发校验)或'submit'(表单提交触发校验)。 4. message(错误提示信息):指定校验失败时的错误提示信息。 以下是一个示例代码,展示了如何在el-form-renderer使用el-form-item进行校验规则的定义: ```html <el-form-renderer :model="formData" :rules="formRules"> <el-form-item label="用户名" prop="username"> <el-input v-model="formData.username"></el-input> </el-form-item> </el-form-renderer> ``` ```javascript data() { return { formData: { username: '' }, formRules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 6, max: 12, message: '用户名长度在6到12个字符之间', trigger: 'blur' } ] } }; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值