1
revalue OP 封装成组件为了减少这个组件内的“组件参数”和“组件配置”的重复填写?是一个层面,但是其减少的填写量远远不如对 echarts 这些组件的再次封装的效果。在这个封装问题里面,这种必要性不是很充分。
|
2
TsubasaHanekaw 2020-06-08 10:54:55 +08:00
这种东西最终成品就是 用户可以通过拖控件方式 自定义表单
|
3
codermagefox 2020-06-08 12:58:46 +08:00
这种问题其实都是表面问题,归根到底就是:
究竟要不要给用户掌握编程能力?如果给,给到什么级别?编程能力究竟应该给开发者还是用户? |
4
Qinmei 2020-06-08 13:19:02 +08:00
我不是很赞同这种设计模式, 表单一般都是 UI 框架封装好的, 我们直接调用组件即可, 那对于前端来说, 直接写组件跟写 json 其实没差别, 但是加了一层之后, 我们不仅要知道 json 层的规则, 我们还要知道组件的规则, 有点多余了;
我更倾向于只抽象逻辑, 但是前端这块其实很少有 |
5
revalue OP @codermagefox 想到 dreamweaver 就知道这个选择题不好做了。现成的阿里开源出来的 Fusion 、飞冰这些,还是马马虎虎。
|
6
SingeeKing 2020-06-08 13:31:11 +08:00
歪个楼,微信小程序只能这么干( html 组件自动转换基本就是废的),然后用起来真的就十分不爽
|
7
no1xsyzy 2020-06-08 13:34:16 +08:00
区分封装和代码生成器,说到底是因为没有 “宏”( AST 层面的宏)
lisp 大家族欢迎你(误 |
9
forbreak 2020-06-08 13:46:31 +08:00
我现在也在这么干,最终是为了通过拖拉控件实现自定义表单。拖拉完成表单直接在线使用。如果生成 template,我不能直接使用,需要再次打包,重启才能用。 建的的表单拖拉一下很方便,就是复杂业务处理这块暂时还没有好的方式。
|
10
redbuck 2020-06-08 13:52:38 +08:00
应用场景还是有的.
比如一些弹窗查询之类的. 可以在他的基础上再封装为函数. const result = await formAction({ fields: [ {type: ''}, ... ] }) 比起封装为组件要灵活一些. |
11
ql9075 2020-06-08 14:01:49 +08:00
当你遇到大量重复页面,重复的 ui 你就会想到这些页面 不同的都是数据。为什么不抽象出来,让数据来控制页面的展示。你不用关心 css, html 的具体实现,如果你想快速配置页面只需了解 json 数据配置,如果你想做更复杂的应用,你可以修改底层逻辑更抽象的封装。
|
12
jrtzxh020 2020-06-08 14:15:45 +08:00
开发如 EPR 这种重复繁琐的 UI,还是很有必要的。
|
13
dodo2012 2020-06-08 14:27:06 +08:00
我现在做 vue 表单就是自己实现的拖拉生成,其实这东西,只要统一好接口方式,没那么麻烦的
|
14
toesbieya 2020-06-08 14:34:55 +08:00
写动态组件用 render 是最好的
|
15
felixpy 2020-06-09 00:57:52 +08:00
隔壁楼主来了哈哈。老哥的关注点好像在 UI 框架的适配器上了,其实我感觉这个这个不是重点。复杂业务场景下大部分表单元素都是需要封装成一个支持 v-model 的自定义表单组件的,只有少部分的没啥逻辑的组件能用上适配器。如果业务的自定义组件需要用 hack 的方式插入 slot,那我觉得是这个自定义组件的抽象程度还不够。
另外,我也同意你的观点,简单的页面完全没必要使用 JSON 配置的方式,自己在 template 组织即可。 JSON 配置的方式其实是为了解决一类问题。假设我们有一个商品录入系统,总共需要录入 50 种类别的商品,每一类商品需要通过表单字段填写 30 条的信息。其中这些表单的特点如下: - 不同类别商品需要填写的表单字段 80% 可以进行复用,但是相同字段在每个类别下可能校验规则、可选择项、提示语等不同 - 字段与字段之间具有一些相同的联动规则,比如不管在其中 20 个商品类别下,只有填写了字段 A 才能填写字段 B 这种情况,我相信大家都不会写 50 个表单页,自己在每个表单页再去组织这些组件,同时处理各种不一样的地方。 |
17
felixpy 2020-06-09 01:10:31 +08:00
@forbreak 复杂业务的处理可以把封装到自定义组件里面,如果是通用的逻辑可以抽象到 composition-api 里面。另外如果一个组件在不同场景下有不同的业务逻辑,就可以考虑抽象成一个 组件选项 来控制。
|
18
revalue OP @felixpy 啊不是,我觉得你没有理解我的意思,你太过客气了。
我司就是已经跑过了 15 楼说的那个阶段,现在最大的问题是如 17 楼所说,所谓的“组件选项”太多了。 “组件选项”只有 0 个或无数个,如果作为后来接手这些模块的人,你就能感受到压力了。 |
19
revalue OP 你这组件选项,控制的不是某 ui 组件,而是控制一个里面一堆 ui 组件的黑盒,我说这才是麻烦的地方
|
20
wly19960911 2020-06-09 09:35:37 +08:00
@revalue 那问题是 template 无法维护,你不用文档和需求固定下来,无限制的扩张扩展性根本是一个无法维护的怪物。今天这个人一个这样的需求,明天那个另外一个需求,我做这个的最大原因就是固定功能,几十个奇葩功能的表单,表单多达 30 多个字段,每次 template 都得写 1000 行,这种代码就好维护了?
|
21
revalue OP 首先“需求常变更调整”是另外一个问题,是侧面影响这个问题的因素。
如果把 1000 行 template 用 json Schema 来描述,就会变好了吗?除非你把后端发过来的 json 直接拿来用。json Schema 来描述,你的 template 就要考虑是否循环遍历 json 然后渲染了,只是最多把一些默认的配置封进去而已,如果这些默认设置不满意,就需要加组件参数去改。我说的就是这种参数特别难维护。 |
22
wly19960911 2020-06-09 09:55:39 +08:00
@revalue 这种参数很难维护吗?无非就是根据计算属性来处理相关的多个参数合并操作,而且我用的数据结构类似 echarts 的 series,不同的 type 不同的选择项,加上完全的 typescript 注释和工厂类创建。维护业务组件的正常操作而已。不满意继续加新的 type,老的组件不动,开发新的组件来逐步替换老组件
而且新的需求上来了,你也要去改老组件啊...这种遍历循环 json 的组件真的没什么难做的,难做的是那些带 if 逻辑的 json schema,我也没兴趣做,因为完全没必要,我这里效果太差了。 |
23
taowen 2020-06-09 13:46:16 +08:00
一个解决方案本身并没有对错和好坏,要看这个解决方案是解决什么问题的。我尝试列举三个问题:
* jsx / tsx 等方案的编程反馈周期慢,一个界面的修改,从改源代码到看到效果需要好几秒钟(如果 webpack 等优化不好的话)。 * 最终用户需要能够自定义自己的界面,比如店铺要装修,报表需要自定义的仪表盘。 * CRUD 写得太烦躁了,每个都差不多。但是每个又有不同。 从这三个问题出发,都有动机自己在现有的前端技术上架一层。 * 拿 JSON/XML 等方式定义一个自己的模板语言,自己写一个解释器,然后支持拖拽。所见即所得的 GUI Designer,解决了反馈周期慢的问题。 * 给用户一个店铺装修器,生成的描述文件存数据库。渲染的时候取出来,动态执行。 * CRUD 就不用说了。解释器的方案就是动态代码生成。静态代码生成是另外一条路。仅仅是生成的话,静态动态区别不大。难点在于 20%不同的逻辑,怎么指定。静态的方案要比动态的方案更好做一些。 每个不同的问题,对于最终这个方案好还是坏的定义都不同。每个问题都有自己细微的难点,比如 Gui Designer 怎么表达复杂的响应式排版,CRUD 怎么表达差异的逻辑部分等。做出一个 60 分的解决方案,可能带来的收益,还不足以支付切换解决方案带来的成本。 |
26
wisetc 2020-06-09 19:44:40 +08:00 via iPhone
还是 json 大法好,这种我用过的,适合大表单,好处是利于测试,以及可以赋初值。看下面的定义就晓得了,属性超级多。
```ts enum Widget { div, radio, radioGroup, select, date } interface Option { label: string; value: string; } interface Field { label: string; hideLabel?: boolean; id: string; type: Function; hidden: boolean; labelAsSuffix?: boolean; defaultValue?: any; belongsTo?: string; widget?: Widget; required?: boolean; options?: Option[]; fetchMethod?: () => Promise<any>; delayFetchMethod?: () => Promise<any>; suffixText?: String; postMethod?(val: any): any; fieldSet?: Field[]; close?: boolean; rest?: object; } ``` 随手定义的分享出来,不过自己写的,别人未必能看懂。 |