为什么我反对在 ui 组件库之上,再作对 template 进行 for 循环遍历 json 的封装? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
revalue
V2EX    Vue.js

为什么我反对在 ui 组件库之上,再作对 template 进行 for 循环遍历 json 的封装?

  •  2
     
  •   revalue 2020-06-08 10:27:13 +08:00/span> 4516 次点击
    这是一个创建于 1957 天前的主题,其中的信息可能已经有所发展或是发生改变。
    看到隔壁贴,/t/679490 ,这个老哥最终成品方向还不确定,我也不是针对这个老哥的模式。我把其一个可能的方向简化的话就类似于这个链接 https://www.cnblogs.com/wisewrong/p/9052467.html 。(代码超级简单)

    这个原理也很简单,就是在 vue template 上 for 遍历这个 json,通过 if else 得出最后的 vue dom,就是这样封装。其实这个循环加封装就损失掉了 template 的可拓展性,应对复杂的场景,你必须用 hack 的方式设立并传个 slot 进去这个组件把损失掉的 template 拓展性给补回来。然后你这种 hack 又要加字段说明。像这样,每个人往上面补一刀,之后这个模块基本上就废了。

    除非你这个 json 设计,可迁移和可拓展性很强,比如你 json 还有别的用途,能拓展出新的配套功能配套设施。否则我觉得这是“脱裤子放屁”,这种封装只是把数据换了一种形式来表达,从 html 转为同等的 json,代码量几乎没减少,只能说在个别人看来,js object 比一大段 html 代码要美观一点。我组里已经有很多同学做成这个样子作为封装来邀功,“百花齐放”,封装后调用接口不一,我觉得用起来太难受了。

    我不是说反对 json Schema 。而是反对根据 json Schema 来在 template 上 for 循环遍历然后 if else 。其他的比如根据 json 代码生成 template 代码,我是比较看好的。

    PS:我想了下为什么封装那么难,以至于我更提倡代码生成器,是因为 vue 的 2.x 版本没有提供对 template 的“业务逻辑”的封装。受 react hooks 影响,在最近两年其他框架新版本开始有对业务逻辑的封装。而对比来看,像 vue 如果去封装“ui 组件库”,问题不是很大的。
    26 条回复    2020-06-09 19:44:40 +08:00
    revalue
        1
    revalue  
    OP
       2020-06-08 10:41:53 +08:00
    封装成组件为了减少这个组件内的“组件参数”和“组件配置”的重复填写?是一个层面,但是其减少的填写量远远不如对 echarts 这些组件的再次封装的效果。在这个封装问题里面,这种必要性不是很充分。
    TsubasaHanekaw
        2
    TsubasaHanekaw  
       2020-06-08 10:54:55 +08:00
    这种东西最终成品就是 用户可以通过拖控件方式 自定义表单
    codermagefox
        3
    codermagefox  
       2020-06-08 12:58:46 +08:00
    这种问题其实都是表面问题,归根到底就是:

    究竟要不要给用户掌握编程能力?如果给,给到什么级别?编程能力究竟应该给开发者还是用户?
    Qinmei
        4
    Qinmei  
       2020-06-08 13:19:02 +08:00
    我不是很赞同这种设计模式, 表单一般都是 UI 框架封装好的, 我们直接调用组件即可, 那对于前端来说, 直接写组件跟写 json 其实没差别, 但是加了一层之后, 我们不仅要知道 json 层的规则, 我们还要知道组件的规则, 有点多余了;

    我更倾向于只抽象逻辑, 但是前端这块其实很少有
    revalue
        5
    revalue  
    OP
       2020-06-08 13:23:11 +08:00
    @codermagefox 想到 dreamweaver 就知道这个选择题不好做了。现成的阿里开源出来的 Fusion 、飞冰这些,还是马马虎虎。
    SingeeKing
        6
    SingeeKing  
    PRO
       2020-06-08 13:31:11 +08:00
    歪个楼,微信小程序只能这么干( html 组件自动转换基本就是废的),然后用起来真的就十分不爽
    no1xsyzy
        7
    no1xsyzy  
       2020-06-08 13:34:16 +08:00
    区分封装和代码生成器,说到底是因为没有 “宏”( AST 层面的宏)
    lisp 大家族欢迎你(误
    billLiao
        8
    billLiao  
       2020-06-08 13:44:48 +08:00 via Android
    @Qinmei #4
    forbreak
        9
    forbreak  
       2020-06-08 13:46:31 +08:00
    我现在也在这么干,最终是为了通过拖拉控件实现自定义表单。拖拉完成表单直接在线使用。如果生成 template,我不能直接使用,需要再次打包,重启才能用。 建的的表单拖拉一下很方便,就是复杂业务处理这块暂时还没有好的方式。
    redbuck
        10
    redbuck  
       2020-06-08 13:52:38 +08:00
    应用场景还是有的.
    比如一些弹窗查询之类的.

    可以在他的基础上再封装为函数.
    const result = await formAction({
    fields: [
    {type: ''},
    ...
    ]
    })

    比起封装为组件要灵活一些.
    ql9075
        11
    ql9075  
       2020-06-08 14:01:49 +08:00
    当你遇到大量重复页面,重复的 ui 你就会想到这些页面 不同的都是数据。为什么不抽象出来,让数据来控制页面的展示。你不用关心 css, html 的具体实现,如果你想快速配置页面只需了解 json 数据配置,如果你想做更复杂的应用,你可以修改底层逻辑更抽象的封装。
    jrtzxh020
        12
    jrtzxh020  
       2020-06-08 14:15:45 +08:00
    开发如 EPR 这种重复繁琐的 UI,还是很有必要的。
    dodo2012
        13
    dodo2012  
       2020-06-08 14:27:06 +08:00
    我现在做 vue 表单就是自己实现的拖拉生成,其实这东西,只要统一好接口方式,没那么麻烦的
    toesbieya
        14
    toesbieya  
       2020-06-08 14:34:55 +08:00
    写动态组件用 render 是最好的
    felixpy
        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 个表单页,自己在每个表单页再去组织这些组件,同时处理各种不一样的地方。
    felixpy
        16
    felixpy  
       2020-06-09 01:00:40 +08:00
    @toesbieya 渲染函数很强大也很晦涩,可以考虑下 JSX 之类的
    felixpy
        17
    felixpy  
       2020-06-09 01:10:31 +08:00
    @forbreak 复杂业务的处理可以把封装到自定义组件里面,如果是通用的逻辑可以抽象到 composition-api 里面。另外如果一个组件在不同场景下有不同的业务逻辑,就可以考虑抽象成一个 组件选项 来控制。
    revalue
        18
    revalue  
    OP
       2020-06-09 09:30:48 +08:00
    @felixpy 啊不是,我觉得你没有理解我的意思,你太过客气了。

    我司就是已经跑过了 15 楼说的那个阶段,现在最大的问题是如 17 楼所说,所谓的“组件选项”太多了。

    “组件选项”只有 0 个或无数个,如果作为后来接手这些模块的人,你就能感受到压力了。
    revalue
        19
    revalue  
    OP
       2020-06-09 09:31:51 +08:00
    你这组件选项,控制的不是某 ui 组件,而是控制一个里面一堆 ui 组件的黑盒,我说这才是麻烦的地方
    wly19960911
        20
    wly19960911  
       2020-06-09 09:35:37 +08:00
    @revalue 那问题是 template 无法维护,你不用文档和需求固定下来,无限制的扩张扩展性根本是一个无法维护的怪物。今天这个人一个这样的需求,明天那个另外一个需求,我做这个的最大原因就是固定功能,几十个奇葩功能的表单,表单多达 30 多个字段,每次 template 都得写 1000 行,这种代码就好维护了?
    revalue
        21
    revalue  
    OP
       2020-06-09 09:46:26 +08:00
    首先“需求常变更调整”是另外一个问题,是侧面影响这个问题的因素。

    如果把 1000 行 template 用 json Schema 来描述,就会变好了吗?除非你把后端发过来的 json 直接拿来用。json Schema 来描述,你的 template 就要考虑是否循环遍历 json 然后渲染了,只是最多把一些默认的配置封进去而已,如果这些默认设置不满意,就需要加组件参数去改。我说的就是这种参数特别难维护。
    wly19960911
        22
    wly19960911  
       2020-06-09 09:55:39 +08:00
    @revalue 这种参数很难维护吗?无非就是根据计算属性来处理相关的多个参数合并操作,而且我用的数据结构类似 echarts 的 series,不同的 type 不同的选择项,加上完全的 typescript 注释和工厂类创建。维护业务组件的正常操作而已。不满意继续加新的 type,老的组件不动,开发新的组件来逐步替换老组件

    而且新的需求上来了,你也要去改老组件啊...这种遍历循环 json 的组件真的没什么难做的,难做的是那些带 if 逻辑的 json schema,我也没兴趣做,因为完全没必要,我这里效果太差了。
    taowen
        23
    taowen  
       2020-06-09 13:46:16 +08:00
    一个解决方案本身并没有对错和好坏,要看这个解决方案是解决什么问题的。我尝试列举三个问题:

    * jsx / tsx 等方案的编程反馈周期慢,一个界面的修改,从改源代码到看到效果需要好几秒钟(如果 webpack 等优化不好的话)。
    * 最终用户需要能够自定义自己的界面,比如店铺要装修,报表需要自定义的仪表盘。
    * CRUD 写得太烦躁了,每个都差不多。但是每个又有不同。

    从这三个问题出发,都有动机自己在现有的前端技术上架一层。

    * 拿 JSON/XML 等方式定义一个自己的模板语言,自己写一个解释器,然后支持拖拽。所见即所得的 GUI Designer,解决了反馈周期慢的问题。
    * 给用户一个店铺装修器,生成的描述文件存数据库。渲染的时候取出来,动态执行。
    * CRUD 就不用说了。解释器的方案就是动态代码生成。静态代码生成是另外一条路。仅仅是生成的话,静态动态区别不大。难点在于 20%不同的逻辑,怎么指定。静态的方案要比动态的方案更好做一些。

    每个不同的问题,对于最终这个方案好还是坏的定义都不同。每个问题都有自己细微的难点,比如 Gui Designer 怎么表达复杂的响应式排版,CRUD 怎么表达差异的逻辑部分等。做出一个 60 分的解决方案,可能带来的收益,还不足以支付切换解决方案带来的成本。
    xingyuc
        24
    xingyuc  
       2020-06-09 14:29:07 +08:00
    @jrtzxh020 上百个页面弹窗里面的输入框,cell……想想就可怕
    xingyuc
        25
    xingyuc  
       2020-06-09 14:35:55 +08:00
    @taowen 网易博客、QQ 空间的效果么
    wisetc
        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;
    }
    ```

    随手定义的分享出来,不过自己写的,别人未必能看懂。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4890 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 05:39 PVG 13:39 LAX 22:39 JFK 01:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86