UI 提供的 progress-step 要怎么实现?
前言
这天突然收到了 UI
修改设计稿的消息通知:“xxx 已修改 xxx 项目并 @ 了你,请及时查看变更内容
”,一条、两条、三条 …,修改消息铺天盖地而来,然后就什么都看不到了()因为我选择开启消息免打扰
,但没多久产品就非常贴心的询问是否已经收到了对应的消息,自然免不了还要介绍一下本次修改的内容和原因(
)。消息免打扰失效
于是,我()打开了设计稿正打算好好欣赏欣赏,不曾想一道光芒一闪而过(心甘情愿的
),看到了这样的内容:是谁拉开了窗帘
而这个显示方式之前使用的是 Steps 步骤条 的方式展示的,类似于:
意味着要从一个 Steps 步骤条 改变成一个 progress-step 流程节点 的形式,这很难实现吗?不难!很容易实现吗?倒也未必!
【扩展】假设现在有个面试官就用这个 progress-step
组件作为场景题,想想你该如何描述对这个组件的设计思路!!!
组件设计基本原则
撸起袖子一把梭?
千万先别急着撸起袖子开干,咱们先来聊聊组件设计的基本原则,往往一把梭哈的代码容易形成一个糅杂着各种逻辑的组件,因为这样的设计是脆弱的,很容易带来副作用和难以预知的结果,需求不变更还好,需求要是频繁变更,那么主要问题就会出现,可能因为一个原因去改变组件,就会破坏其他的职责(行为),于是你不得不在多处都进行修改。
怎么知道一个组件复不复杂,这就要看组件内部到底维护了多少和自身状态相关的数据,即非 props
传入的数据,对于现在的 Vue / React
而言都是可以通过 数据来驱动视图 的,用一个函数式表示即 UI = render(data)
或 UI = f(data)
,这意味着一个组件至少需要做到 数据(data) 和 视图(UI) 的解耦。
单一职责
单一职责原则(SRP - single responsibility principle) 中的 职责 是什么,你可以理解为是组件的 行为,这个行为可以是渲染一个列表、展示一张图片、发起一个请求等等,当组件的这个行为发生修改,意味着这个组件本身发生了变化,此时该组件就是 单一职责 的。
为什么不能多职责?
大部分人经常会选择忽视一个组件的多个职责带来的缺陷,这里举个常见查询页面的例子:
- 一部分是和查询条件相关的表单部分
- 负责和用户进行各种交互,比如表单联动、表单重置、表单折叠等等,同时它需要收集、提供用户已经填入的数据
- 一部分是展示查询结果的表格部分
- 将接口响应的数据展示在表格中,同时也要支持与用户的各种交互,比如切换页码、页大小、上一页、下一页、跳转页等
- 一部分是负责将表单数据发送给服务器进行数据交互,即发起请求
假设此时按照 撸起袖子一把梭 的原则去编写这个组件(页面),一定会将表单交互、表格交互、发起请求、处理响应等逻辑混在一个组件(页面)当中:
- 表单的交互逻辑需要维护(行为 1)
- 表格的交互逻辑需要维护(行为 2)
- 请求的发起和响应的处理也需要维护(行为 3)
假设现在接口响应的数据结构发生了变化,在当前的组件(页面)中,你可能需要重新修改处理判断不同响应状态码下页面的表现,同时还得修改表格的展示方式,又或者需要根据响应的数据内容自动填充表单,但由于数据结构的变化还得去调整表单相关的部分,此时仅仅一个数据结构改变的原因就可能影响了三个部分的内容,因为它们耦合了。
多职责的缺陷:
- 组件内容相互耦合,当需求变更时存在相互破坏的可能
- 组件内容各个部分的逻辑杂糅,不易于阅读和维护
- 经过不断的迭代会使得单个组件代码量不断增大
让组件具有单一职责
关于这一点,你完全可以从你平时在项目中使用到的 UI
组件库中去看看,比如 Element UI
中表单相关的组件就分为:
- Form 组件负责整体表单的展示形式和对整体数据的处理
- FormItem 组件单个具体的表单组件的展示形式和单个表单的数据处理
- Input、Select、Option 等等具体的表单组件
基于此还是将上述的例子改变成单一职责:
- 表单部分需要单独封装成组件,主要提供表单展示形式、交互能力、数据处理能力
- 表格部分需要单独封装成组件,主要负责提供对数据展示、交互的能力
- 查询页面(组件)负责提供发起请求数据和处理数据响应的能力,并将表单组件和表格组件组合在一起
这样一来,即便后续响应的数据结构发生改变,也不需要再去修改表单和表格部分的内容,而是在当前的查询页面(组件)中处理好对应的数据格式即可,比如将接收到的数据处理成符合表格或表格组件需要的格式即可。
单一职责的优点:
- 单个组件的内容独立分离,需求变更时只需要修改对应组件
- 单个组件逻辑只存在于该组件中,保证组件代码的简洁性、易读性和维护性
- 在不断迭代中,只需要修改对应组件的内容,不会导致页面中的其他组件代码量增大
通用性
组件的核心是需要体现在业务中的,在项目中的大多数组件都属于业务组件,不具备通用性,因为具有通用性的组件不应该只满足于某个业务,因此组件的设计要考虑从业务中抽离。
设计通用性组件应该考虑什么
- 数据(data) 和 视图(UI) 的解耦
- 见过不少人封装组件就真的只是将原页面内容单纯的剪切出去,视图部分大多是硬编码,除此之外组件维护了七七八八的状态,巴不得这个组件在外部使用的时候什么都不用传递,这样的组件显然不具备通用性,因此一定要将数据和视图进行解耦
- 保证组件的 单一职责(行为)
- 复用一个组件时,是为了重复使用其职责(行为),而只有单一职责的组件才能够被更好的复用,多个单一职责的组件就能更好的实现 组合性,如果一个组件错误地拥有多个职责时,就会增加复用时的开销
- 组件只提供 最基础的 DOM 和 交互逻辑
- 不要让一个组件将视图相关的 DOM 完全掌控在内部,应该将容易变化的部分交给使用者自己去定义(如利用插槽),比如
Element UI
中的Table
组件就提供了render-header(Table-column Attributes)、header(Table-column Scoped Slot)、append(Table Slot)
用于自定义渲染
- 不要让一个组件将视图相关的 DOM 完全掌控在内部,应该将容易变化的部分交给使用者自己去定义(如利用插槽),比如
- 组件封装应该 隐藏内部细节和实现意义,通过
props
控制具体行为和输出- 保证组件的纯度,减少组件的副作用,比如不要在组件中直接使用一些全局变量等,因为这不符合封装的特性,还容易带来不可预测的行为
- 组件封装保证 可测试性
- 组件的可测试性也决定着组件封装的通用性,如果在为一个组件编写测试用例时需要非常复杂,那么大致是组件设计存在问题
设计 progress-step 组件
接下来,就该看看到底该如何分析和设计这个 progress-step 组件了,上面我们提到了最基本的要做到 数据(data) 和 视图(UI) 的解耦,那实际上也就意味着要从这两个大的方向去考虑。
视图(UI)
确定视图展示方式
拿到视图肯定要进行分析,UI 图展示的不一定全面,因此必须要确定所有可能的展示方式,在和产品沟通的过程中确认了这个视图的三种展示形态:
-
串行展示,类似于:
-
并行展示,类似于:
-
混合展示,类似于:
但你仔细查看 UI 稿的设计,其实完全可以将它归类为第二种展示方式,否则你还得为这个 UI 图单独实现另一种展示方式,并且在和产品的沟通中也得到了同意。
确定实现方式
首先,肯定得去看看社区中是否有类似的方案可以直接使用,或者经过小的改动可以被使用的,奈何业务就是业务,果然没找到合适的,但在查找方案的时候也了解到了几种实现方案:
- 基于普通 DOM 元素实现
- 基于 SVG 实现
- 基于 Canvas 实现
最后两种方案,我看到的大多是需要支持各种可比较复杂的拖拽、复制、连接的方式,并且其具体实现也是比较复杂,如果其其不是很熟悉的话,无论在实现还是在后续的各种调整上会花费大量时间,而且如上的一个需求无非是一些展示和简单的交互,并不需要涉及如此复杂的各种自定义操作。
再举个例子,比如前面提到的 Steps 步骤条 也是基于普通 DOM 元素实现的,并且也确实没有太多需要用户自定义的操作。因此,可以将 progress-step 组件当做 Steps 步骤条 的升级版,另外考虑开发时间的限制,选择方案一是最合适的。
确定实现细节
上述展示方式虽然有三种,但实现时可以先实现最简单的 串行展示 方式, 而 并行展示 其实相当于三条串行展示的合并,分别是上边、中间、下边的串行方式,最后的 混合展示 其实只要你实现了前面两种方式,这种方式无非是相当于组件的递归渲染,只不过位置上需要做一些处理:
- 串行展示
- 单节点的 虚线 和 箭头 可以借助元素的伪元素
::before、::after
并通过定位实现
- 单节点的 虚线 和 箭头 可以借助元素的伪元素
- 并行展示
- 上下边的部分仍然可以看做是串行节点的展示
- 中间的部分可以通过一个元素来实现边框效果,并且可以认为是前后节点与这个边框的串行版本
- 混合展示
- 实现了前面两种模式,混合展示方式其实就只是根据数据来进行组件递归渲染
数据(data)
作为前端肯定要具备看到 UI 就能大致设想出其对应 data 的基本结构,而且上述经过视图分析之后,已经得到其对应的三种具体展示形式,在真正开始写代码前,请先把需要封装的组件涉及的核心数据结构给设计好,毕竟这个数据最终是需要从外部传入的:
-
串行展示
- 多个节点,意味着整体应该设计为一个数组
- 单个节点即对应数组的每一项元素信息
data = [{status: 'completed' , name: '完成' }, {status: 'processing' , name: '当前处理节点' }, {status: 'pending' , name: '待处理' } ]
-
并行展示
- 可以看做是上下两个串行展示的合并,可将数据带有并行的节点也使用数组来表示
data = [{status: 'completed' , name: '开始' }, [ // 1. 这个数组表示是并行节点[ // 1.1 这个数组表示是并行节点中,上边 串行节点的数据{status: 'completed' , name: '完成' }, {status: 'processing' , name: '当前处理节点' }, {status: 'pending' , name: '待处理' }],[ // 1.2 这个数组表示是并行节点中,下边 串行节点的数据{status: 'completed' , name: '完成' }, {status: 'processing' , name: '当前处理节点' }, {status: 'pending' , name: '待处理' }]],{status: 'pending' , name: '结束' }, ]
- 混合展示
- 相当于并行节点中又包含并行节点,类似于:
data = [{status: 'completed' , name: '开始' }, [ // 1. 这个数组表示是并行节点[ // 1.1 这个数组表示是并行节点中,上边 串行节点的数据{status: 'completed' , name: '完成' }, [// 1.1 这个数组表示是并行节点中的并行节点[// 1.1.1 这个数组表示是并行节点中,上边 串行节点的数据{status: 'processing' , name: '当前处理节点' }], [// 1.1.2 这个数组表示是并行节点中,下边 串行节点的数据{status: 'processing' , name: '当前处理节点' }], ],{status: 'pending' , name: '待处理' }],[ // 1.2 这个数组表示是并行节点中,下边 串行节点的数据{status: 'completed' , name: '完成' }, {status: 'processing' , name: '当前处理节点' }, {status: 'pending' , name: '待处理' }]],{status: 'pending' , name: '结束' }, ]
实现 progress-step 组件
其大部分的实现思路已经在上面介绍过了,这里就不再额外介绍一些样式计算相关的内容,下面直接展示效果和源码。
props 简介
- data:要展示的节点数据
- colors:不同节点状态的颜色
- status:不同节点状态的值
- size:节点图标的大小
- stepWidth:节点占据的宽度
- space:节点之间的间距
const props = withDefaults(defineProps<PropsType>(), {data: () => [],colors: () => ["#d2d2d2", "#3a84fb", "#67d36f"],status: () => ["pending", "processing", "completed"],size: 25,stepWidth: 80,space: 20,
});
效果展示
串行展示
const data = [{ status: "completed", title: "开始", description: "这是描述" },{ status: "processing", title: "处理中", description: "这是描述" },{ status: "pending", title: "待处理", description: "这是描述" },{ status: "pending", title: "结束", description: "这是描述" },
]
并行展示
const data = [{ status: "completed", title: "开始", description: "这是描述" },[[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "completed", title: "已完成", description: "这是描述" },{ status: "pending", title: "待处理", description: "这是描述" },],[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "pending", title: "待处理", description: "这是描述" },],],{ status: "pending", title: "结束", description: "这是描述" },
]
混合展示
const data = [{ status: "completed", title: "开始", description: "这是描述" },[[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "completed", title: "已完成", description: "这是描述" },[[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "pending", title: "待处理", description: "这是描述" },],[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "processing", title: "处理中", description: "这是描述" },]],{ status: "pending", title: "待处理", description: "这是描述" },],[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "completed", title: "已完成", description: "这是描述" },[[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "pending", title: "待处理", description: "这是描述" },],[{ status: "completed", title: "已完成", description: "这是描述" },{ status: "processing", title: "处理中", description: "这是描述" },]],{ status: "pending", title: "待处理", description: "这是描述" },],],{ status: "pending", title: "结束", description: "这是描述" },
]
不足
现存缺点比较明显:
- 当流程节点超过视图容器,很难动态调整好各个节点间的距离,现在暂时使用滚动条代替
- 不能无限制渲染节点层数(最大层数为 3 ,如混合模式所示),动态计算方式仍存在缺陷
- 节点内容变化导致高度、位置的计算问题
- …
源代码
需要查看代码的可通过此处查阅:源代码
代码目录
最后
在实际实现过程中涉及到动态计算的部分很容易理不清,包括动态计算矩形框高度、宽度以及节点位置等,以上仅仅算是一个实现思路(不要害怕写出不完美的代码
),期望各位小伙伴能够在评论区给出更优质的方案!!!
相关文章:

UI 提供的 progress-step 要怎么实现?
前言 这天突然收到了 UI 修改设计稿的消息通知:“xxx 已修改 xxx 项目并 了你,请及时查看变更内容”,一条、两条、三条 …,修改消息铺天盖地而来,然后就什么都看不到了(因为我选择开启消息免打扰…...

DBSwitch和Seatunel
一、DBSwitch 什么是DBSwitch?它主要用在什么场景? 通过步骤分析可以看到这个是通过配置数据源,采用一次性或定时方案,同步到数据仓库的指定表,并且指定映射关系的工具。有点类似于flinkcdc的增量同步。 参考: dbs…...
【日志】力扣刷题 -- 轮转数组
2024.10.06 【力扣刷题】 经典面试150—转轮数组—中等 189. 轮转数组 - 力扣(LeetCode) 第一次做,暴力循环 // 超出时间限制 void rotate(int* nums, int numsSize, int k) {for(int i 0; i < k; i){int right numsSize - 1;int temp…...
Java 项目 Dockerfile 示例:从基础镜像选择到环境变量配置的详细指南
Java 项目 Dockerfile 示例:从基础镜像选择到环境变量配置的详细指南 本文提供了一个 Java 项目的 Dockerfile 示例,展示了如何为 Java 应用创建高效的 Docker 镜像。Dockerfile 从 OpenJDK 8 的 Java 运行环境开始,配置了工作目录和 JVM 启…...

WebGL编程指南 - 高级变换与动画基础
学习使用一个矩阵变换库,该库封装了矩阵运算的数学细节。快速上手使用该矩阵库,对图形进行复合变换。在该矩阵库的帮助下,实现简单的动画效果。 矩阵变换库:cuon-matrix.js OpenGL中的函数: 书中 cuon-matrix.js 函数…...

银行客户贷款行为数据挖掘与分析
#1024程序员节 | 征文# 在新时代下,消费者的需求结构、内容与方式发生巨大改变,企业要想获取更多竞争优势,需要借助大数据技术持续创新。本文分析了传统商业银行面临的挑战,并基于knn、逻辑回归、人工神经网络三种算法࿰…...

制程质量管理方案设计
质量管理系统框架——QMS 涵盖产生产制造体系的全生命周期的质量管理过程 与SAP、WMS、MES、OA等业务系统进行集成,整合各业务系统中的质量信息 利用整合的全价值链质量信息,寻找质量改进点和质量创新点 系统功能模块管理 系统管理:用户管理…...

uniapp移动端优惠券! 附源码!!!!
本文为常见的移动端uniapp优惠券,共有6种优惠券样式(参考了常见的优惠券),文本内容仅为示例,您可在此基础上调整为你想要的文本 预览效果 通过模拟数据,实现点击使用优惠券让其变为灰色的效果(模…...
【分布式技术】中间件-zookeeper安装配置
文章目录 安装部署1. 安装ZooKeeper2. 配置ZooKeeper3. 启动ZooKeeper服务器4. 使用ZooKeeper命令行客户端5. 使用ZooKeeper的四个基本操作6. ZooKeeper集群模式7. 安全和权限8. 监控和日志 相关文献 安装部署 在Linux环境中操作ZooKeeper通常涉及以下几个方面: 1…...
高等数学 7.6高阶线性微分方程
文章目录 一、线性微分方程的解的结构*二、常数变易法 方程 d 2 y d x 2 P ( x ) d y d x Q ( x ) f ( x ) (1) \cfrac{\mathrm{d}^2 y}{\mathrm{d}x^2} P(x) \cfrac{\mathrm{d}y}{\mathrm{d}x} Q(x) f(x) \tag{1} dx2d2yP(x)dxdyQ(x)f(x)(1) 叫做二阶线性微分方程。…...

LSP的建立
MPLS需要为报文事先分配好标签,建立一条LSP,才能进行报文转发。LSP分为静态LSP和动态LSP两种。 静态LSP的建立 静态LSP是用户通过手工为各个转发等价类分配标签而建立的。由于静态LSP各节点上不能相互感知到整个LSP的情况,因此静态LSP是一个…...

huggingface的数据集下载(linux下clone)
1. 安装lfs sudo apt-get install git-lfs 或者 apt-get install git-lfs 2. git lfs install git lfs install 3. git clone dataset包 第2,3步骤的截图如下:...

Java使用dom4j生成kml(xml)文件遇到No such namespace prefix: xxx is in scope on:问题解决
介绍addAttribute和addNamepsace: addAttribute 方法 addAttribute 方法用于给XML元素添加属性。属性(Attributes)是元素的修饰符,提供了关于元素的额外信息,并且位于元素的开始标签中。属性通常用于指定元素的行为或样式&#…...
深入探讨Java中的LongAdder:使用技巧与避坑指南
文章目录 一、什么是LongAdder?二、LongAdder的简单使用示例代码: 三、LongAdder的工作原理四、LongAdder的常见使用场景五、使用LongAdder时的注意事项(避坑指南)1. 不要滥用LongAdder2. sum()方法与精度问题3. 避免过度使用rese…...

【本科毕业设计】基于单片机的智能家居防火防盗报警系统
基于单片机的智能家居防火防盗报警系统 相关资料链接下载摘要Abstract第1章 绪论1.1课题的背景1.2 研究的目的和意义 第2章 系统总体方案设计2.1 设计要求2.2 方案选择和论证2.2.1 单片机的选择2.2.2 显示方案的选择 第3章 系统硬件设计3.1 整体方案设计3.1.1 系统概述3.1.2 系…...

C语言 动态数据结构的C语言实现单向链表-2
建立一个单向链表 在单向链表中查找节点---查找尾节点 在单向链表中查找节点 --- 查找第 n 个节点 向单向链表中插入一个节点 向单向链表的尾部插入一个节点 向单向链表中某节点后插入一个节点 向单向链表中插入一个节点 删除单向链表中的某一节点 链表 vs 数组 动态数据结构...
Github 2024-10-23C开源项目日报 Top10
根据Github Trendings的统计,今日(2024-10-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10PLpgSQL项目1Redis - 内存数据库和数据结构服务器 创建周期:5411 天开发语言:C协议类型:BSD 3-Clause “New” or “Revised” Licen…...
ubuntu20.04 opencv4.0 /usr/local/lib/libgflags.a(gflags.cc.o): relocation报错解决
在一个只有ubuntu20.04的docker环境中配置opencv4.0.0, 什么库都没有,都要重新安装, 其他的问题在网上都找到了解决方案,唯独这个问题比较棘手: [ 86%] Linking CXX executable …/…/bin/opencv_annotation /usr/bin/ld: /usr/lo…...

android openGL ES详解——混合
一、混合概念 混合是一种常用的技巧,通常可以用来实现半透明。但其实它也是十分灵活的,你可以通过不同的设置得到不同的混合结果,产生一些有趣或者奇怪的图象。混合是什么呢?混合就是把两种颜色混在一起。具体一点,就…...

计网--物理层
目录 物理层的任务 1、常见概念 2、信道极限容量 3、传输介质 (1)导引型传输介质 (2)非导引型传输介质 4、信道复用技术 (1)频分 / 时分 复用 (2)波分复用WDM (…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...