可视化搭建 - 场景实战

news2024/11/26 13:53:54

接下来用实战来说明该可视化搭建框架是否好用,以下几条原则需要始终贯穿在下面每个实战场景中:

  1. 复杂的业务场景,背后使用的框架 API 是简单的。

  2. 底层 API 并不为业务场景特殊编写,而是具有很强的抽象性,很容易挖掘出其他业务场景的用法。

  3. 所有场景都是基于有限的几条基础规则实现,即背后实现的复杂度不随着业务场景复杂度提升而提升。

上卷下钻

上卷下钻其实是 组件作用于自身的筛选

所以上卷下钻背后的实现原理应该与筛选、联动一样。利用 setValue 在点击下钻按钮时,修改组件自己的 value,然后通过 valueRelates 让该组件的联动作用于自身,剩下的逻辑就和普通筛选、联动没有太多区别了,区别仅仅是联动触发源是自己:

import { ComponentMeta } from "designer";

const chart: ComponentMeta = {
  componentName: "chart",
  element: Chart,
  // 利用 runtimeProps 将组件 value 映射到 props.value,将 props.onChange 映射为 setValue 修改自身 value
  runtimeProps: ({ selector, setValue, componentId }) => ({
    value: selector(({ value }) => value),
    onChange: (value: string) => setValue(componentId, value),
  }),
  // 自己联动自己
  valueRelates: ({ componentId }) => [
    {
      sourceComponentId: componentId,
      targetComponentId: componentId,
    },
  ],
  fetcher: ({ selector }) => {
    // relates 可能来自自己、其他筛选器组件实例,或者其他图表组件实例
    const relates = selector(({ relates }) => relates);
    // 根据 relates 下钻 ...
  },
};

上卷下钻就是作用于自身的联动。

Tabs 组件

利用组件树解析规则,我们任意找一个 Key 存放每个 TabPanel 的子元素就可以了。

我们利用 props.tabs 存放 tabs 配置,props.content 存放每项 TabPanel 的子组件,因为其顺序永远和 props.tabs 保持一致,我们可以简单的使用下标匹配。

const tabs = {
  componentName: "tabs",
  element: TabsComponent,
  defaultProps: {
    // 存放 tabPanel 配置
    tabs: [
      {
        title: "tab1",
        key: "1",
      },
    ],
    // 存放每个 tabPanel 内子画布的组件实例
    content: [
      {
        componentName: "gridLayout",
      },
    ],
  },
};

而 TabsComponent 组件实现就完全与平台解耦了,即使用 props.tabsprops.content 渲染即可:

const TabsComponent = ({ content, handleAddTab, handleDeleteTab, tabs }) => (
  <Tabs
    editable
    defaultActiveTab="1"
    onAddTab={handleAddTab}
    onDeleteTab={handleDeleteTab}
  >
    {tabs.map((tab, index) => (
      <TabPane key={tab.key} title={tab.title}>
        {content[index]}
      </TabPane>
    ))}
  </Tabs>
);

tabs 使用 treeLike 结构,按照下标存储组件实例。

富文本内嵌组件实例

与 tabs 很像,区别是富文本内嵌入的组件实例数量是不固定的,每一个组件实例都对应富文本某个 block id. 下面是富文本实现代码的一部分:

const SomeRichTextLibrary = (props) => {
  // 自定义渲染 block 槽位
  const RenderCustomBlock = useCallback(
    (blockId: string) => {
      // 渲染组件实例
      return props.blockElements.find(
        (componentInstance) => componentInstance.componentId === blockId
      );
    },
    [props.blockElements]
  );
};

富文本一般拥有自定义 block 区块的能力,我们只要将 block id 与组件实例 id 绑定,然后将组件实例存储在 props.blockElements,就可以轻松匹配到对应组件实例了。

其中 props.blockElements 的结构如下:

{
  "blockElements": [
    {
      "componentId": "block1",
      "componentName": "chart"
    },
    {
      "componentId": "block2",
      "componentName": "radar"
    }
  ]
}

富文本的结构可能如下:

{
  "type": "rich_text",
  "content": [
    {
      "type": "paragraph",
      "text": "This is a paragraph of rich text."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "This is a heading"
    },
    {
      "type": "block",
      "blockId": "block1"
    },
    {
      "type": "block",
      "blockId": "block2"
    }
  ]
}

最后两个 block 是自定义区块,通过自定义 RenderCustomBlock 来渲染,我们正好可以通过 blockId 对应到 componentId,在 props.blockElements 中找到。

富文本的实现思路和 tabs 基本一样,只是查找组件实例的逻辑不同。

实现任意协议

我们也许为了进一步抽象,或对指定业务场景降低配置门槛,在组件树拓展一些额外的 json 结构协议做一些特定功能。

以拓展事件配置为例,假如我们需要实现如下协议:每个组件实例信息上拓展了 events 属性,通过配置这个属性可以实现一些内置动作,如打开 Modal。这个协议至少要定义触发源是什么 trigger、做什么事情 type 以及作用的目标组件 targetId:

{
  "componentName": "button",
  "events": [
    {
      "trigger": "onClick",
      "type": "openModal",
      "targetId": "123"
    }
  ]
}

如上面的例子,只要定义好触发源、类型和目标组件,就可以在按钮组件 onClick 时将目标组件 visible 设为 true,实现弹出 Modal 的效果。

实现思路是,利用 onReadComponentMeta,在所有组件的元信息做拓展。比如要拓展这种事件,一般 Trigger 都要绑定在组件 Props 的回调上(如果是全局监听,可以绑定在全局并利用事件机制通信给组件),那就可以通过 runtimeProps 进行绑定:

const App = () => (
  <Designer
    onReadComponentMeta={(meta) => ({
      ...meta,
      runtimeProps: (options) => {
        const result = meta.runtimeProps?.(options) ?? {};
        const events = options.selector(
          ({ componentInstance }) => componentInstance.events
        );
        events?.forEach((event) => {
          switch (event.type) {
            case "openModal":
              // 给组件添加新的 trigger 绑定
              result[event.trigger] = options.setRuntimeProps(
                event.targetId,
                (props) => ({
                  ...props,
                  visible: true,
                })
              );
              break;
          }
        });
        return result;
      },
    })}
  />
);

除此之外,我们还可以想象有更多的协议可以通过这种方式处理响应,无论何种协议,背后都是基于组件元信息的实现,易懂且单测有保障。

总结

本文我们总结了三个场景实战:

  1. 利用 treeLike 结构在组件内渲染任意数量的子组件实例,如 tabs 或富文本。

  2. 利用组件联动的 API,实现筛选、联动以及上卷下钻。

  3. 利用 onReadComponentMeta 为所有组件元信息统一增加逻辑,用来解读如 props 属性中定义的某些规则,进而实现任意协议。

讨论地址是:精读《可视化搭建 - 场景实战》· Issue #485 · dt-fe/weekly

如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。

关注 前端精读微信公众号

9fe941a291cf3bcf3980aa8f195ea4c9.jpeg

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/587362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

23种设计模式之状态模式(State Pattern)

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章将23种设计模式中的状态模式&#xff0c;此篇文章为一天学习一个设计模式系列文章&#xff0c;后面会分享其他模式知识。 如果文章有什么需要改进的地方还请大佬不…

Zabbix API开发实战,创建报警媒介和代码示例(付源码)

Zabbix API开始发挥重要作用&#xff0c;尤其是在Zabbix与第三方软件&#xff08;如配置和事件管理系统&#xff09;的集成以及日常任务的自动化方面。如果没有一些自动化&#xff0c;管理对数千台主机的监控是非常困难的。 API是在Zabbix 1.8中引入的&#xff0c;并且已经被广…

多语言电商系统_国际化电商系统流程

跨境电商系统是基于计算机技术和互联网平台的一种电子商务系统。它通常包括前端电商网站或应用程序、后台管理系统、物流管理系统、支付系统等多个模块&#xff0c;可以通过网络实现商品展示、订单管理、支付结算、物流配送等电商流程的自动化处理。 跨境电商系统基本流程包括…

JWT | 一分钟掌握JWT | 概念及实例

作者&#xff1a;Mars酱 声明&#xff1a;本文章由Mars酱编写&#xff0c;部分内容来源于网络&#xff0c;如有疑问请联系本人。 转载&#xff1a;欢迎转载&#xff0c;转载前先请联系我&#xff01; 什么是JWT JWT的全称是Json Web Token。是基于RFC 7519开放标准的&#xff…

玩转ChatGPT:视频制作

一、写在前面 最近&#xff0c;在码深度学习图像识别的相关知识和代码&#xff0c;这一part&#xff0c;看看能否用小Chat搞一个介绍视频。 简单问小Chat&#xff1a; 咒语&#xff1a;我怎么使用你做一个视频&#xff1f;需要配合什么软件生成&#xff1f;&#xff1f; 大意…

2023.5.22-5.28 AI行业周刊(第149期):毕业10年后的实验室聚会

周末和实验室&#xff0c;无锡这边师兄弟们相聚了一次&#xff0c;之前在无锡这边的江南大学读书&#xff0c;后来工作后大家大多数也都留在了无锡。 我们研究生时的实验室&#xff0c;专门有一个微信群&#xff0c;从02年入学&#xff0c;到17年入学&#xff0c;多年各界的师…

Node.JS学习 | Babel | webpack | ES6

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Node.JS Node.JS能够在服务器端运行JavaScript的开放源代码、跨平台运行环境&#xff1b;Node.js采用Google开发的V8运行代码&#xff0c;使用事件驱动、非阻塞IO和异…

Python常用数据结构

Python 提供了多种内置的数据结构&#xff0c;用于存储和组织数据。以下是一些常见的 Python 数据结构&#xff1a; 1.列表&#xff08;List&#xff09;&#xff1a;列表是一个有序、可变的数据集合&#xff0c;可以包含任意类型的元素。列表使用方括号 [] 表示&#xff0c;元…

谷歌周彦祺:LLM浪潮中的女性科学家多面手丨智源大会嘉宾风采

导读 大模型研发竞赛如火如荼&#xff0c;谷歌紧随OpenAI其后推出PalM2、Gemini等系列模型。Scaling Law是否仍然适用于当下的大模型发展&#xff1f;科技巨头与初创企业在竞争中各有哪些优势和劣势&#xff1f;模型研究者应秉持哪些社会责任&#xff1f; 2023智源大会「基础模…

华为OD机试真题B卷 Java 实现【最长的连续子序列】,附详细解题思路

一、题目描述 有N个正整数组成的一个序列,给定一个整数sum,求长度最长的的连续子序列使他们的和等于sum,返回该子序列的长度,如果没有满足要求的序列返回-1。 二、输入描述 第1行有N个正整数组成的一个序列。 第2行给定一个整数sum。 求最长连续子序列,只要遍历计算连…

补贴平价好书影响上亿读者:有一种力量叫“至拙”

通过一种“至拙”的力量&#xff0c;“多多读书月”带来诸多可喜的变化。 全民拼书&#xff1a;“多多读书月”带来平价好书 如果你也是一位热爱读书的小伙伴&#xff0c;那么想来一定不会不知道“多多读书月”。 2020年&#xff0c;在“三区三州”地区助力脱贫攻坚的公益活动中…

转转前端周刊第六十七期

转转前端周刊 本刊意在将整理业界精华文章给大家&#xff0c;期望大家一起打开视野 如果你有发现一些精华文章想和更多人分享&#xff0c;可以点击我们的公众号名称&#xff0c;将文章链接和你的解读文案发给我们&#xff01;我们会对内容进行筛选和审核&#xff0c;保留你的推…

详细理解GPT2模型结构及其训练过程—GPT系列训练与部署

本文为博主原创文章&#xff0c;未经博主允许不得转载。 本文为专栏《Python从零开始进行AIGC大模型训练与推理》系列文章&#xff0c;地址为“https://blog.csdn.net/suiyingy/article/details/130169592”。 GPT2模型环境搭建与调试请参考博文《GPT系列训练与部署—GPT2环境配…

一分钟学一个 Linux 命令 - ls

前言 大家好&#xff0c;我是 god23bin。今天我给大家带来的是 Linux 命令系列&#xff0c;每天只需一分钟&#xff0c;记住一个 Linux 命令不成问题。今天&#xff0c;我们要介绍的是一个常用而又强大的命令&#xff1a;ls&#xff08;list&#xff09;。 什么是 ls 命令&am…

CVPR 2023 | 去雨去噪去模糊,图像low-level任务,视觉AIGC系列

Learning A Sparse Transformer Network for Effective Image Deraining 基于Transformer的方法在图像去雨任务中取得了显著的性能&#xff0c;因为它们可以对重要的非局部信息进行建模&#xff0c;这对高质量的图像重建至关重要。本文发现大多数现有的Transformer通常使用查询…

Linux的进程信号(下)

文章目录 1. 阻塞信号1.1 信号其他相关常见概念1.2 在内核中的表示 2. sigset_t3. 信号集操作函数3.1 sigprocmask3.2 sigpending3.3. 实例演示 4. 信号的处理4.1. sigaction4.2 多个信号的处理 5. 可重入函数6. volatile7. SIGCHLD信号 1. 阻塞信号 1.1 信号其他相关常见概念…

java基于springboot自来水收费缴费系统+jsp

本次设计拟采用JAVA技术&#xff0c;对乡镇自来水收费系统的功能需求进行了全面分析&#xff0c;从模块功能定义、前后端交互技术、数据库及编程语言的选择、系统调试及测试、功能完善和改进等方面进行设计&#xff0c;解决了从用户新装、抄表、计费、收费、复查、换表、发票管…

Pyside6-第三篇-QToolButton一个奇葩的按钮

今天是Pyside6的第三篇内容。一起来看另一个按钮。 QToolButton。 from PySide6.QtWidgets import QToolButton, QWidget, QApplicationapp QApplication([])win QWidget() win.setWindowTitle("QToolButton按钮")btn QToolButton(win) btn.setText("触发&qu…

Cell揭秘--慢性压力如何导致肠道炎症

大脑产生的信号传导到肠道神经细胞&#xff0c;导致炎症化学物质的释放。 溃疡性结肠炎患者的肠道组织&#xff08;人工着色&#xff09;。图片来源: Steve Gschmeissner/Science Photo Library 心理压力会加重某些肠道疾病引起的肠道炎症。现在&#xff0c;科学家们找到了原因…

初学QT(Day05)

继续第四天的demo 总结了之前的经验教训&#xff0c;我重新开一个项目项目&#xff0c;先给出demo的结果吧&#xff0c;第一张是第一次写的demo&#xff0c;第二张图是成品的demo 结果还是比较满意的&#xff0c;虽然过程中有遇到的问题不是我自己独立解决的。。。相比于第…