技术选型 - 分开or统一(还是会分开

457 阅读6分钟

“我正在参加「掘金·启航计划」”

前言


新的一年,希望大家都身体健康。
大展宏兔🐰。

2.png

一、阐述场景

最近荣幸接手公司的可视化平台。

今天想分享的也不是什么技术难点,主要是一个方案的选择罢了。

就好比有一个场景是这样子的:

比如,我们有一个页面,通过json进行配置出页面进行渲染。

之前有写过一篇:Vue如何高效通过JSX动态渲染组件,该篇有讲解到如何根据标签渲染出组件。

那么,我们回归本次谈论的,在如下页面中,我们怎么通过配置json渲染出该页面呢?

3.png

下面我们进行分析一下🧐。

二、进行分析

2.1 JSON结构

可以想到,在json中,分为两个组,一个是【温馨提示】、另一个是【报备方式】。

  • 【温馨提示】组内有一个文本字段。
  • 【报备方式】组内有一个单选框组件。

我们大概想到把结构划分为:

{
  // 字段
  file:[
   {
       "id": 1,
       "type": 'input',
       "title": '同一证件号当天仅可报备一次',
   },
   {
       "id": 2,
       "type": 'radio',
       "option":[
           { name: 'a.有'value: 'a' },
           { name: 'b.没有', value: 'b' }
       ]
   }
  ],
  // 组
  groupInfos: [
    {
      "name": "温馨提示",
          "ids":[ 1 ] // ids绑定的是file上面的id集合 
    },
    {
      "name": "报备方式",
      "ids":[ 2 ]
    }
  ]
}

2.2 Style

我们还要对其设置字体大小、颜色等,于是,我们还要对其进行样式的编写。

对上面的json,添加styleGlobalConfig配置【行row】、【左label】、【右field】样式属性。

{
    ...
    styleGlobalConfig:{
      "row": "display: flex;flex-direction: column;", // 行样式 
      "label": "font-size: 16px;color: #666666;",  // 左边的标题样式
      "field": "font-size: 16px;"                  // 右边的组件样式
    }
}

然后把styleGlobalConfig属性里面的row、label、field属性添加到组件中的:style绑定。

这种配置,只适用于整个页面的布局是一样的。

2.3 样式需分为全局、组、项

但是,通常来说,我们的页面可能不是每一个组的布局都一样的。

比如,我们组1可能是左右布局的,组2可能是上下布局的,那么当前的styleGlobalConfig对象将无法配置。

4.png

5.png

于是,我们的styleGlobalConfig被当做是全局的样式配置,那么我们还需要【单个组】的样式配置起为groupStyle,以及【单个项】的配置起为fildStyle

{
  // 字段
  file:[
   {
       "id": 1,
       "type": 'input',
       "title": '同一证件号当天仅可报备一次',
       "fildStyle": { 
           "label": "",                   // 左边的标题样式
           "field": 'color: #999999;'     // 右边的组件样式
       },
   },
   {
       "id": 2,
       "type": 'radio',
       "option":[
           { name: 'a.有'value: 'a' },
           { name: 'b.没有', value: 'b' }
       ]
   }
  ],
  // 组
  groupInfos: [
    {
      "name": "温馨提示",
          "ids":[ 1 ] // ids绑定的是file上面的id集合 
    },
    {
      "name": "报备方式",
      "ids":[ 2 ],
      "groupStyle":{ 
          // 我们对组2的row,布局为上下布局
          "row": "flex-direction:column;",             // 行样式
          "label": "font-size: 16px;color: #666666;",  // 左边的标题样式
          "field":"margin-left:-10px;"                 // 右边的组件样式
      },
    }
  ],
  // 全局样式
  styleGlobalConfig:{
      "row": "display: flex;flex-direction: column;", // 行样式 
      "label": "font-size: 16px;color: #666666;",  // 左边的标题样式
      "field": "font-size: 16px;"                  // 右边的组件样式
    }
}

三、可能有更好的方案?

以上,单独对各自的【组】、【项】有着各自的样式配置,看似还不错。

今天讲的技术选型,那应该还有第二种方案,可能有人可能会问了,这样子分散配置,会不会太麻烦了?

3.1 统一管理

应该统一放在一个对象styleConfig里面进行样式配置,统一管理。

目前我们的样式配置都放在styleConfig中。

  • public:为公共样式;
  • groupStyle:为单个组的样式;
  • fildStyle:为单个项的样式;
"styleConfig": {
    // 公共样式
    public:{
        "row": "display: flex;align-items: center;",
        "label": "font-size: 16px;color: #666666;",
        "field": "font-size: 16px;"
    },
    // 各个组的
    group:[
        {
            // 单个组的样式
            groupStyle:{},
            // 行的样式
            fildStyle:[
                {
                    "label": "font-size: 16px;color: #666666;",
                    "field": "font-size: 16px;",
                },
                ...
            ]
        },
        {
            groupStyle:{
                "row": "flex-direction:column;",
                "label": "font-size: 16px;color: #666666;",
                "field":"margin-left:-10px;"
            },
            ...
        }
    ]
  },

3.2 如果我要设置第六组的样式,那前面五组都要设置空对象了?

因为,我们是按照组group的顺序进行渲染样式绑定的。

问题也很好解决,给他们加上id绑定关联即可。

渲染改为根据id,不是根据顺序绑定。

如下代码中的id: 6,我可以在group数组中写上id: 6,第六组单独写,前面不需要写空对象,而且顺序可以随便写。

"file":[{}],
"styleConfig": {
    // 公共样式
    public:{
        "row": "display: flex;align-items: center;",
        "label": "font-size: 16px;color: #666666;",
        "field": "font-size: 16px;"
    },
    // 各个组的
    group:[
        {
            id: 1,
            // 单个组的样式
            groupStyle:{},
            // 行的样式
            fildStyle:[
                {
                    // 该id的来源是上方的file数组中的各个项的id
                    "id": "1_1",   
                    "label": "font-size: 16px;color: #666666;",
                    "field": "font-size: 16px;",
                },
                ...
            ]
        },
        {
            // 如此,我就可以在第六组单独写,前面不需要写空对象,而且顺序可随便写
            id: 6,
            groupStyle:{
                "row": "flex-direction:column;",
                "label": "font-size: 16px;color: #666666;",
                "field":"margin-left:-10px;"
            },
            ...
        }
    ]
  },

看起来,貌似还不错。

我们确实是做到了都在styleConfig对象中配置样式,但是这样子也会顺势带来结构的复杂化,还要去管理id关联关系。

四、样式权重

扩展一个话题,就是样式权重问题。

比如:

  • 全局设置了color:green;
  • 组设置了color:pink; font-size:16px;
  • 项设置了:color:red;

那么,最终是

color:red;
font-size:16px;

也就是他们的样式属性会叠加,但相同属性以后者为准,会覆盖上面之前的。

即,样式权重:全局 < 组 < 项。

🙋那么,在代码中,如何写叠加呢?

🙋🏻‍♂️利用动态样式:style,可以用 + ,让他们进行叠加。

截取组件中,其中的项的标题样式写法:

先写全局的,加上组的,加上项的,这样子会以后面的为权重最高。

:style="styleConfig.label + group.groupStyle.label + fild.label"

我们需要注意一下,当一个不配置,为null时,后面的会被无效化。

如:styleConfig.label没配置为null时;

后面的group.groupStyle.label + fild.label不会执行。

:style="null + group.groupStyle.label + fild.label"

所以,我们需要做下空判断,如果为空,给她赋值空字符串即可。

基于此,我们封装一个方法,getVal和toVal方法。

解读getVal方法:如果对象styleConfig为空,那么styleConfig.label会报错,getVal方法调用后会返回null。

这时,再配合toVal,为null,给他赋值为空字符串即可。

<div 
  :style="toVal(styleConfig, 'label') + toVal(group, 'groupStyle', 'label') + toVal(fild, 'label')"
>
</div>

6.png

源码如下传送门,搜索【getVal】

后记

以配置样式的场景,有两个方案:

  • 分开配置:分为【全局】、【组】、【项】,扩展性可能会更灵活,想配组6就配组6

  • 统一管理:全都在一个对象styleConfig配置,需管理id

其实,两种方案都是可以的。各有千秋。

相信帅气的你们,看本篇的标题就已经知道我最后选了哪种。

就是分开配置。

7.png

🙋为啥?

🙋🏻‍♂️因为除了以上提到的,还有一个历史原因,之前的组件代码,页面都是通过styleConfig对象进行配置的。

也就是说,如果我选择了方案二,之前的styleConfig,就变成了styleConfig.public,需要做一下兼容写法。

方案一,还是保留了styleConfig全局样式,只不过在此基础上,扩展了两个属性【组groupStyle】、【项fildStyle】。

选择方案一,也是考虑到没有那么多的关联关系,之后会更加灵活,毕竟是加在已有对象中,扩展属性而已。

还是会分开,还是会怪你。
怪你轻而易举潇洒抽离。
还是爱着你,想走进你统一
拨开迷雾抓住你的声音。

👍 如果对您有帮助,您的点赞是我前进的润滑剂。

以往推荐

三面:请设计一个虚拟DOM算法吧!

Vue3的响应式到底比Vue2优雅在哪

开局面试官就让我设计一个路由

实战v-model如何绑定多循环表达式(内含原理)

靓仔,说一下keep-alive缓存组件后怎么更新及原理?

面试官问我watch和computed的区别以及选择?

面试官问我new Vue阶段做了什么?

多图详解,一次性啃懂原型链(上万字)

Vue-Cli3搭建组件库

Vue实现动态路由(和面试官吹项目亮点)

VuePress搭建项目组件文档

原文链接

juejin.cn/post/720227…