基于vue通用表单解决方案的思考与分析


Posted in Javascript onMarch 16, 2019

前言

“那要怎么改?”,“那得改到什么时候?”,“什么时候才能支持这些功能?”。

再一次听到了这样的话,我沉默了。到底要怎样改,这也是我所思考的,最近一直忙于其他,已经有一段时间没有处理 issue 了,趁着调休,我也要好好思考下。

半年前,接触了 el-form-renderer  ,瞬间感觉减轻了大部分表单编写的工作,一个简单的JSON配置,立刻展现出一个功能完好的表单页面。然而,随着使用的频率增加,却慢慢开始暴露各种不足,该组件的作者也不再单独对该组件进行维护了。由于项目表单场景的需要,我们 fork 了一个版本,但后来发现我们更想要的是一套属于我们自己的表单渲染规则,于是在我们的 Github 组织下建立了属于我们的代码仓库 @femessage/el-form-renderer  (以下都称为 el-form-renderer ),并开始了我们自己维护之路。

3W

el-form-renderer 是什么?为什么?怎么样?通过3W分析来看看我们做了什么。

WHAT?

基于 element-ui 封装的 表单渲染器 ,但不仅仅是 element-ui ,甚至不仅仅是表单。

基于vue通用表单解决方案的思考与分析

WHY?

这里的为什么有两层,第一层是为什么需要表单渲染器?第二次是什么是 el-form-renderer ?

借用《NoForm - 一个更好的表单解决方案》中的一句话:

做 B类业务 的同学应该深有感触,我们日常需要面对大量操作类或者表单类的场景,因此只要是能从这些重复的CRUD解放出来的方案,就是最好的方案

我们的目的也很简单,让天下没有难做的表单。

至于为什么是 el-form-renderer ,理由很简单,我们正在让没有难做的表单变成现实,至少在目前数十个项目中,解决了70%以上的表单方面的需求。

HOW?

如上文所说,如下图所见:

基于vue通用表单解决方案的思考与分析

一个好的表单需要解决的问题:

•表单的取值、赋值、校验

•表单联动

•自定义表单项

•表单项的事件、属性、slot

•对用户足够友好

所谓”下层基础决定上层建筑“,我们没有执着于从0开始,而是“让专业的人做专业的事”。基础组件, element-ui 足够专业,也正因为它的专业性,才让 el-form-renderer 最初的版本有了用武之地。然而目前远远不够的是,我们没有很好的处理表单联动和表单项的事件、slot的问题,这也正是我所要思考的地方。

基础用法

先来看看目前我们的实现(更多请参考 文档 )

<template>
 <el-form-renderer label-width="100px" :content="content" />
</template>
<script>
import UploadToAli from '@femessage/upload-to-ali'
export default {
 data () {
 return {
 content: [
 {
 $id: 'avatar',
 label: '头像',
 component: UploadToAli
 },
 {
 $id: 'username',
 label: '用户名',
 $type: 'input',
 $el: {
 placeholder: '请输入用户名'
 }
 }
 ]
 }
 }
}
</script>

效果如下:

基于vue通用表单解决方案的思考与分析

没有复杂的逻辑,只需进行简单配置 JSON 的方式就可实现常用表单功能

解决方案

因为不是从0开始,所以一开始作者的设计只服务于 element-ui 已有的组件。

之前的方案解决了什么

• 表单的取值 getValue ,赋值 updateValue

• 完整继承了 element 的 form 表单属性,包括校验

• 表单联动 $enableWhen

大部分简单的场景已经覆盖,但是局限于 element-ui 组件,没有处理好动态组件选项(如下拉选项)的问题,无法批量赋值,必须手动去空格...

现在的方案优化了什么

• 支持自定义组件,摆脱对 element-ui 的完全依赖(仍然依赖它的 el-form , el-form-item )

• 通过 setOptions 方法,动态的处理组件选项问题

• 添加批量更新数据方法 updateForm ,并添加 trim 来处理值

• 为了方便在其他组件中的集成和设置/获取值的需求,还添加了 inputFormat 、 outputFormat ( issue )

它本已完成了一个华丽的蜕变,甚至成为了我司组件的桥梁地位,然而,面对千奇百怪的需求,它确实还不够。

存在的问题

基于vue通用表单解决方案的思考与分析 

目前的7个 issue ,大致可以分为一下几类:

•表单联动

•自定义slot位置

•自定义事件

•其他优化

需求告诉我们,它还有很大的进步空间。

思考

回到开始的那些话,面对存在的问题,我们要怎么处理好它。

今天收到一个 PR ,来自公司的一位同事,处理的是 el-form-renderer 中 slot 位置的问题,默认只有 default ,显示在最后,有需求希望能显示在指定某一个表单项的前/后。该PR以表单项的 $id 为具名插槽,渲染该插槽内容到对应 $id 表单项的上方。

一个很好的思路,但是也让我思考了很多,或许它还是没有达到我的要求。

不妨再思考一个场景,表单的第一项和第三项渲染的上方需要渲染两个内容相同的 slot ,按上面的思路,我们应该写两个template,并分别定义他们要渲染到的位置的的 $id 。

上面的问题并不难解决,定义一个字符串匹配规则,或者在某一项的配置项中添加要渲染的slot,名字匹配则渲染,以达到复用的目的。

问题似乎是解决了, issue 可以关闭了,但是我们回过头来想想,我们为什么要自定义 slot 位置?

因为有issue,有用户有这个需求。

那他为什么会有这个需求?

我们不得而知,场景很多,但我们可以大胆的猜测,缺乏一个组件可以满足他的渲染需求,他需要 slot 来自定义展示内容。

所以,似乎我们需要的并不是 slot ,而是我们缺乏了那些组件,或者我们需要一个更通用的渲染方式来渲染我们的内容。很容易,我们想到了 render ,如果我们返回的是一个 render ,那似乎大部分 issue 可以关闭了。然而事实是,我们从开始就不希望出现 render ,因为它一点都不友好,甚至对部分人来说,它不简单,这不是我们的目的。 我们的目的是为了更好用,更好理解,就向我们的文档一样,它很简单,但很实用 。

许多PR,或者打算提PR的人忽略了一个问题,我们的组件没有支持事件,它很难实现?不,至少已经实现了绑定属性,绑定事件并不会多难,但是没有去支持它,因为我们 思考的是它的必要性 ,表单项是否真的需要绑定事件。

从一开始就说过,不只是 element-ui ,甚至不只是表单。我们的目的不纯粹,我们寻找的是通用的方案,如果支持了事件,表单项与业务代码的关联性绝对会更强,这不是我们希望看到的,至少在我们目前可以看得到的通过可视化的界面生成表单的前提下,我们不希望出现自定义事件的需求,它让我们通过可视化的界面生成表单变得不那么通用了。

那么,在目前的情况下,真的没办法解决这些问题了吗?答案是否定的。

已知我们可以通过自定义组件的方式拓展我们的表单项,那么我们也可以通过自定义组件解决我们遇到的 issue

import CustomComponent from './custom-component'

export default {
 data () {
 return {
 content: [
 {
 label: '用户名',
 component: CustomComponent,
 $id: 'username',
 $el: {
 placeholder: '请设置您的登陆用户名'
 }
 }
 ]
 }
 }
}

或者在一些更简单的场景

import UploadToAli from './UploadToAli'

export default {
 data () {
 return {
 content: [
 {
  $id: 'avatar',
  label: '图片',
  component: {
  data () {
  return {
  imgUrl: ''
  }
  },
  render: function (h) {
  return h(UploadToAli, {
  props: {
   value: this.imgUrl
  },
  on: {
   input: (val) => {
   this.imgUrl = val
   this.$emit('input', val)
   }
  }
  }, [
  h('p', {
   slot: 'spinner'
  }, '开始上传中...')
  ])
  }
  }
 }
 ]
 }
 }
}

如果从这个层面来说,我们早已经解决问题了,但是那些 issue 依然在那儿。还记得之前提过的对用户足够友好和 render 的事吗,目前来看,它能解决问题,但不是一个好的方案,解决问题并没有那么难,难的是解决了还能足够友好,足够简单,这也是我们一直在努力的方向。

结语

不知不觉写了好长...

通过配置的方式实现一个表单似乎是一个不错的思路,目前已经在公司中后台有过数十个页面的尝试。然而业务场景千变万化,我们没有办法解决100%的需求,但希望我们的方式为配置性表单能带来更多的思考。

抛砖引玉,最后贴一次仓库地址: https://github.com/FEMessage/el-form-renderer ,希望更多的方案和实现浮出水面,解放生产力。再次感谢 原作者

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
表单提交前触发函数返回true表单才会提交
Mar 11 Javascript
javascript判断是否按回车键并解决浏览器之间的差异
May 13 Javascript
Node调试工具JSHint的安装及配置教程
May 27 Javascript
JavaScript学习心得之概述
Jan 20 Javascript
js闭包实现按秒计数
Apr 23 Javascript
每个程序员都需要学习 JavaScript 的7个理由小结
Sep 03 Javascript
React.Js添加与删除onScroll事件的方法详解
Nov 03 Javascript
vue将毫秒数转化为正常日期格式的实例
Sep 16 Javascript
微信小程序 flexbox layout快速实现基本布局的解决方案
Mar 24 Javascript
vue实现购物车功能(商品分类)
Apr 20 Javascript
解决vue项目获取dom元素宽高总是不准确问题
Jul 29 Javascript
Vue实现手机计算器
Aug 17 Javascript
vue+php实现的微博留言功能示例
Mar 16 #Javascript
一些你可能不熟悉的JS知识点总结
Mar 15 #Javascript
使用element-ui table expand展开行实现手风琴效果
Mar 15 #Javascript
element-ui组件table实现自定义筛选功能的示例代码
Mar 15 #Javascript
vue过滤器用法实例分析
Mar 15 #Javascript
vue v-for循环重复数据无法添加问题解决方法【加track-by='索引'】
Mar 15 #Javascript
详解vue移动端项目代码拆分记录
Mar 15 #Javascript
You might like
单位速度在实战中的运用
2020/03/04 星际争霸
调频问题解答
2021/03/01 无线电
PHP获取类中常量,属性,及方法列表的方法
2009/04/09 PHP
php 目录与文件处理-郑阿奇(续)
2011/07/04 PHP
PHP数据源架构模式之表入口模式实例分析
2020/01/23 PHP
Chrome中模态对话框showModalDialog返回值问题的解决方法
2010/05/25 Javascript
JavaScript Title、alt提示(Tips)实现源码解读
2010/12/12 Javascript
JS高级笔记
2011/07/13 Javascript
JS中引用百度地图并将百度地图的logo和信息去掉
2013/09/29 Javascript
jQuery+ajax实现鼠标单击修改内容的思路
2014/06/29 Javascript
jquery实现图片随机排列的方法
2015/05/04 Javascript
jQuery插件FusionCharts实现的Marimekko图效果示例【附demo源码】
2017/03/24 jQuery
基于bootstrop常用类总结(推荐)
2017/09/11 Javascript
jquery实现图片跟随鼠标的实例
2017/10/17 jQuery
利用babel将es6语法转es5的简单示例
2017/12/01 Javascript
浅谈React之状态(State)
2018/09/19 Javascript
vue实现的组件兄弟间通信功能示例
2018/12/04 Javascript
Vue.js递归组件实现组织架构树和选人功能
2019/07/04 Javascript
antd中table展开行默认展示,且不需要前边的加号操作
2020/11/02 Javascript
jQuery实现动态向上滚动
2020/12/21 jQuery
进一步探究Python中的正则表达式
2015/04/28 Python
浅析Python中的赋值和深浅拷贝
2017/08/15 Python
Python多图片合并PDF的方法
2019/01/03 Python
python批量修改文件夹及其子文件夹下的文件内容
2019/03/15 Python
Python何时应该使用Lambda函数
2019/07/02 Python
Python使用lambda表达式对字典排序操作示例
2019/07/25 Python
python 实现两个npy档案合并
2020/07/01 Python
Python 合并拼接字符串的方法
2020/07/28 Python
美国专业级皮肤病和spa品质护肤品的高级零售网站:SkinCareRx
2017/02/06 全球购物
德国柯吉澳趣味家居:Koziol
2017/08/24 全球购物
物业保安主管岗位职责
2013/12/25 职场文书
我的中国梦演讲稿300字
2014/08/19 职场文书
2015年营业员工作总结
2015/04/23 职场文书
个人工作违纪检讨书
2015/05/05 职场文书
拔河比赛新闻稿
2015/07/17 职场文书
Python3中PyQt5简单实现文件打开及保存
2021/06/10 Python