• 前端进击笔记第十七节 提升开发效率:数据抽象与配置化


    上一讲介绍了如何对前端应用进行模块化和组件化设计,是一个对系统设计进行抽象的过程。实际上,我们在业务功能开发过程中,也会在很多地方使用到抽象的能力,比如将页面内容抽象为数据展示,将页面的呈现方式抽象为状态。

    通过抽象的方式,我们可以将整个前端应用使用数据的方式来进行表达和描述,还可以配合配置化来减少硬编码、提升功能的灵活性。

    今天我就主要介绍如何将应用抽象成数据,以及怎么配合配置化来提升代码的可维护性。

    如何将应用抽象成数据

    要将应用抽象成数据,需要进行两个步骤:

    1. 将应用进行模块化和组件化划分;

    2. 将这些模块和组件用数据的方式进行表达。

    上一讲我介绍了对前端应用进行模块化和组件化划分的一些原则,下面我会直接介绍将页面划分成模块和组件的例子。

    将页面划分成模块和组件

    在进行系统设计和开发代码之前,产品经理首先会进行功能设计。产品经理在设计一个页面的时候,会根据内容和功能的不同,设计出不同的模块,将它们呈现在页面中。

    对于前端开发来说,我们会拿到功能需求描述以及 UI 设计图。此时我们需要结合功能说明以及交互稿或者设计图,来进行逆向拆解,即把一个页面按照功能和内容划分出一个个的模块。

    以我自己的博客为例:

    image.png

    我们直观地根据视觉来划分模块,可以分为三大块。

    • 头部:快速导航栏

    • 左侧:内容板块

    • 右侧:推广导航板块

    上一讲我们说过,组件可理解为带有界面渲染的特殊模块,因此上述这些模块也可以视作为组件。论坛类、博客类的页面结构大多如此,除此之外还有视频类、电商类等各种角色的网站,大都可以划分为内容模块(详情页/列表页)、导航模块(TAB/导航栏/工具栏)、功能组件(回到顶部/翻页组件)等。

    对应用进行模块划分之后,我们可以将划分后的模块抽象成数据的方式来表达。

    将模块/组件抽象成数据

    通常来说,我们可以抽离出应用中存在变化的内容和动态获取的数据,再通过将这些数据与页面内容绑定的方式(比如使用前端框架进行绑定),来控制具体功能的展示。

    我们可以通过数据的来源,将其分成内部数据(状态数据)和外部数据(动态数据)两种。

    1. 内部数据(状态数据)

    在一个应用的设计里,我们可能会有多个组件,每个组件又各自维护着自己的某些状态。其中,部分组件的状态会相互影响,所有状态的结合体便是应用最终的整体状态。这些状态维护在应用内部,可以通过数据的方式来表示,我们简单称之为内部数据(状态数据)。

    怎么定义内部数据呢?最浅显、最直观的办法就是,这些数据来自应用本身,同时影响应用的呈现状态。如对话框的出现和隐藏、标签的激活和失效、进度条的状态等,都可以作为状态数据。

    比如,用户在网页中的一些操作,点击某个按钮之后,会出现弹窗,这个弹窗的展示内容以及是否展示的状态可以用对象来描述。

    const dialog = {
      isShow: true,
      title: "弹窗标题",
      content: "弹窗内容"
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 1
    • 2
    • 3
    • 4
    • 5
    2. 外部数据(动态数据)

    除了应用本身的状态数据,还有很多不属于应用状态的数据,比如文章内容、个人信息等,都是需要从其他地方(服务端、缓存、文件等)获取的。这些需要从外部获取,用于页面展示或是影响展示的一些数据,我们将它称作外部数据(动态数据)。

    外部数据不同于内部数据,它并不会跟随着应用的生命周期而改变,也不会随着应用的关闭而消失。这些数据独立存在于外部,通过动态获取和注入的方式进入应用,从而影响应用的展示内容和功能逻辑。

    举个例子,上面博客中的内容板块为列表页,这样的列表页可以用一个数组来表示:

    const articleList = [
      { id: 333, title: "文章标题", brief: "文章简介", date: "日期" }
      // ...
    ];
    
    • 1
    • 2
    • 3
    • 4
    • 1
    • 2
    • 3
    • 4

    这些数据需要从本地数据库中读取,或者通过 HTTP 请求从服务端获取,再根据获取结果渲染出每个列表的内容。

    我们在设计模块和组件的时候,需要将这些内部数据和外部数据抽离出来,其中内部数据在组件和模块内部进行维护。当应用启动的时候,再通过注入外部数据的方式,使其可以正常运行。

    将数据与应用抽离

    要怎么理解将数据与应用抽离呢?如果将应用比作是一个公司,公司里所有的桌椅、电脑等设备都是静态的,每个工位可理解为一个组件,同时办公室也可以认为是大一点的组件或是模块。

    那么在我们这个公司里:

    • 内部数据是椅子的位置、消耗的电量、办公室的照明和空调状态等;

    • 外部数据是行政人员、技术人员、设计人员等各种人员流动。

    每天上班的时候,一个个的工作人员来到公司里,开始干活,此时公司也开始运作。

    # 将公司和人分开(下班后)
    --------------------------------------------------------
                             公司
    ---------------------------  ---------------------------
    |                                                      |  人           人
    |                                                      |      人          人
    |                         办公楼                        |           人
    |                                                      |   人     人     人  人
    |                                                      |   人      人   人
    ---------------------------  ---------------------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在公司正常运作的时候


                         公司
    
    • 1

    | 人 人 人 人 人 人 人 |
    | 人 人 人 人 人 |
    | 人 人 办公楼 人 人 人 |
    | 人 人 人 人 人 人 人 |

    人 人 人 人 人 人 人

    当然,大家不只是站在工位里这么简单,我们会与各种物件进行交互和反馈(挪动桌椅、开灯开空调等),人与人之间也会相互交流和影响(对需求、方案评审等)。

    如果我们每个人的工位都是随机的,在工作过程中会很不方便,所以大家会被有规律有组织地分别隔离到每个办公室、隔间里面。

    # 按照组织进行分隔
    --------------------------------------------------------
                             公司
    --------------------------------------------------------
    |   人   |  人   人  |         | 人    人    |  人 人    |
    |   人   |     人    |         |    人  人   |   人  人  |
    |--------    人  人  |  办公楼  |  人    人    --------- |
    |     人 |  人       |         |  人     人  |   人  人  |
    |     人 |   人   人 |         | 人     人   |  人   人  |
    --------------------------------------------------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    同样的,我们在设计应用的时候,除了需要考虑如何划分模块、对应用数据进行抽象,还需要将其有规律地管理。当我们将模块和组件的状态和内容抽象成数据之后,就可以将这些数据独立出来进行管理,也可以更好地解决模块/组件间耦合、依赖、通信等问题。

    我们还能观察到,桌椅和其他办公设备其实也可以通过外部获取,也就是说,内部数据同样可以转换为外部数据,通过动态获取的方式来恢复应用之前的状态。比如某个表单在二次编辑的时候,需要恢复为提交时的状态,包括勾选框是否选中、输入框填写的内容等。

    那么,我们将这些数据和应用抽离之后,可以用来做些什么呢?我们可以通过变更数据的方式来更新应用的状态,在第 9 讲中我们也有介绍数据驱动的编程方式。

    我们还可以通过设计合适的状态机,来解决像 Web 页面这种天然异步系统中事件被多次触发问题,比如用户连续点击某个按钮,通过状态判断是否需要进行相应的逻辑处理等。

    除此之外,当我们对数据进行抽象和分离之后,还可以很方便地实现应用的配置化。

    实现应用的配置化

    配置化的思想不仅仅存在于前端或者是某个领域,大多数的系统和功能设计,都可以用领域抽象、数据抽离、配置化等方式,减少需求开发和维护的成本。

    将应用中的数据抽离之后,我们可以对这些数据进行配置。

    可配置的数据

    前面我们介绍了影响应用状态的数据,其中包括了与界面有关和与界面无关的数据。

    当我们希望对某个产品进行配置化调整的时候,一般会使用运营管理平台来进行运营和管理。通过搭起一整套的运营管理平台,我们可以通过平台进行配置,管理应用的状态和数据,包括:

    • 界面展示内容,如活动文案、广告内容、推荐位等;

    • 功能逻辑,比如有效时间的计算、活动上线和下线、是否需要用户输入信息等。

    如果应用功能逻辑通用性较好、复杂程度较低,我们甚至可以通过配置的方式快速搭建出前端页面,比如活动类配置系统、表单类配置系统等。

    对于一些功能简单的页面,页面结构、功能比较相似,区别在于文案不一致、模块位置的调整、颜色的改变等。相比于通过复制粘贴然后调整逻辑,通过抽象和配置化的方式,我们节省重复性的工作,同时还避免了项目过多、重复代码难以维护等问题。

    以上这种简单页面的配置,基本上有两种实现方式:

    1. 根据配置生成静态页面的代码,直接加载生成的页面代码;

    2. 实现通用的功能逻辑,在加载页面的时候动态加载配置数据,从而生成展示的页面。

    配置化的核心大概是场景分析和功能拆解,所以抛开使用场景来做一个所谓“通用”的配置化是不现实的。为了做出合适的配置化功能,我们需要把问题范围局限在解决特定的场景,比如用于电商活动的页面、表单提交类的页面等。

    以一个组件开发为例,我们来看看怎么实现组件的配置化。

    组件配置化

    以下图中的卡片组件来作为例子:

    image (1).png

    为了方便地表达数据绑定,后面的代码会基于 Vue 框架实现。

    我们可以实现以下的配置化能力:状态和展示内容可配置、样式可配置、功能逻辑可配置。

    1. 状态和展示内容可配置

    例如,我们需要一个对话框,其头部、正文文字、底部按钮等功能都可支持配置,我们可以用代码这样表示。

    {{cardInfo.title}}
    {{cardInfo.content}}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过这样的方式,我们可以:

    • 通过cardInfo.hasTitle来控制是否展示头部;

    • 通过cardInfo.buttons来控制底部按钮的数量和文字。

    通过这种配置方式,我们可以控制组件中具体某些功能的状态和展示内容。

    2. 样式可配置

    样式的配置,通常是通过class来实现的,比如可以使用条件语句进行判断,并绑定不同的class

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 1
    • 2
    • 3
    • 4

    通过这样的方式,我们可以控制界面的展示样式。如今很多框架会通过在class里添加随机 MD5 这样的方式,来保持局部作用域的class样式不受其他地方影响。

    除了class之外,我们当然也可以直接将条件语句和style进行绑定,来控制具体的某个样式。

    3. 功能逻辑可配置

    举个例子,我们的这个卡片可以是视频、图片、文字三者其中之一的卡片。

    • 视频:点击播放。

    • 图片:点击新窗口查看。

    • 文字:点击无效果。

    这种时候,我们可以使用这两种方式来实现功能逻辑的配置化。

    • 通过控制 UI 展示来控制点击事件的处理:每个模块(视频、图片、文字)绑定自己的点击事件,同时通过配置控制哪个模块的展示,从而控制事件的处理逻辑。

    • 通过逻辑判断来控制点击事件的处理:绑定的点击事件里,根据配置来进行不同的事件处理,展示不同的效果。

    可以看到,一个组件中可以通过配置的方式来控制它的状态、展示内容、样式,甚至是功能逻辑。而我们的应用常常是通过不同的组件和模块组成的,同样可以通过配置的方式来控制应用的各个状态、内容以及功能。

    小结

    今天我主要介绍了应用中常见的数据抽象,通过对应用进行合适的数据抽象,并将这些数据从应用中抽离从而实现应用的配置化,我们可以减少需要开发的代码量,提升系统的可维护性。

    配置化的思想可以用在各个地方,我们也常常将其称为“一切皆可配置化”。

    实际上,除了页面内容、应用状态的配置化,我们甚至可以实现接口的配置化,比如 GraphQL 可用于自定义的接口 API 查询。

    除了这些,你觉得还有哪些问题可以通过配置化来解决的呢?欢迎在留言区进行讨论。


    精选评论

    **航:

    请教一个问题,比如有这样一种场景,在程序的入口调用了一个或多个接口,然后会根据这些接口的数据(有很多个字段)组合一起来做不同的判断走不同的路由,这样就要写很多个ifelse了,目前有没有一些好的优化方案呢

        讲师回复:

        一般来说,可以将这些判断逻辑按照一定的规则进行拆分,拆分到多个函数中,这样每个函数的职责会更加清晰。但这样并不解决你的判断条件数量,个人认为可以梳理下依赖的判断数据是否合理,可以进行调整。另外,还可以尝试将依赖的数据用一定方式组合,直接根据组合后的数据来判断,比如 a_b_c 这样,可以将三个判断放在一个里。

    **0231:

    微信小程序有什么方案可以配置化搭建页面吗?

        讲师回复:

        配置化的实现,很多时候其实都是针对自身的业务特点,划分出不同类型的组件将其组合,其实跟在哪个平台关系并不大。微信小程序可以结合自定义组件来做。

  • 相关阅读:
    实现免杀:Shellcode的AES和XOR加密策略(vt查杀率:4/70)
    微信小程序 movable-area 区域拖动动态组件演示
    每日练习-8
    AI算法工程师 | 03人工智能基础-Python科学计算和可视化(三)Pandas
    vant的作用及其使用方法
    微信公众号后台管理
    期货穿透式监管实质(期货看穿式监管)
    uniapp中全局页面挂载组件(小程序)
    信息系统项目管理师教程 第四版【第2章-信息技术发展-思维导图】
    Python异步框架大战:FastAPI、Sanic、Tornado VS Go 的 Gin
  • 原文地址:https://blog.csdn.net/fegus/article/details/126315828