Excalidraw 对组件 API 的思考和设计

本文探讨了Excalidraw编辑器新API的设计思路,旨在提供更灵活和可组合的UI定制能力。内容包括摆脱render props,通过组件子项方式实现自定义,如Footer和MainMenu组件。新API利用React.Children筛选组件并渲染,同时允许在没有React的情况下使用编辑器核心功能。文章还介绍了新引入的下拉菜单和欢迎页的自定义选项,并提醒开发者注意组件的层级关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自从去年年底我们公布完成了编辑器的重新设计以来,许多开发人员都迫切地提到了一个问题,那就是什么时候把它发布到 Excalidraw package 中,以及为什么没有在一开始就发布它?

我们没有在第一时间发布 excalidraw.com 的原因是要满足一些定制化开发。在我们的对外公共应用中,有一些内容需要进行硬编码,例如主菜单(main menu)和欢迎页(welcome screen)-- 这些内容可能并不需要在个人的私有应用中进行硬编码 – 我们不太确定如何设计 API 以使其更易于定制。

今天,我们发布了新 API 的初始版本,之前阻塞新版本发布的那部分内容,基本都支持自定义实现。如果大家的给出的反馈是积极的,我们将继续以类似的方式公开更多的 API,以便大家可以根据个人和用户的需要来定制编辑器。

现在介绍一下我们都做了哪些事情,包括我们是如何以及为什么这么做?


作为重新设计的一部分,我们引入了两个新的主要内容:作为主菜单的左上角下拉菜单,以及欢迎页,包括对新用户的提示,以帮助他们了解 UI 的要点。

这里很明确的是,你会根据自己的需要来定制这些功能,更重要的是,移除你自己的应用程序中不需要的部分。

到目前为止,我们一直在使用 config objects(例如 props.UIOptions)和 render props(例如,props.renderFooter)的组合。虽然这些都很好,您可以通过这种方式完成大多数事情,但我们需要更加灵活和可组合的 API,并且使用起来更加直观。

摆脱 render props

我们希望您不仅能够渲染自定义组件(例如自定义页脚),还可以修改默认组件。之前我们通过 render props 来暴露扩展点。虽然 render props 工作得很好,但我们设计了这样一种 API,可以将所有内容都渲染为 Excalidraw 组件的子项,如下所示:

import { Excalidraw, MainMenu, Footer } from '@excalidraw/excalidraw';
import { MyCustomButton } from './MyCustomButton';

export const App = () => (<Excalidraw><MainMenu>{/* menu items */}</MainMenu><Footer><MyCustomButton></Footer></Excalidraw>
) 

未来,我们甚至可能将插件作为组件公开,所以您最终会这样做:

import { Excalidraw, MinimapPlugin } from "@excalidraw/excalidraw";

export const App = () => (<Excalidraw><MainMenu>{/* menu items */}</MainMenu><MinimapPlugin /></Excalidraw>
); 

说到底,这更像是一个美学决定,而不是功能决定,因为我们也可以通过 render props 实现这一点。一个好处是 API 表面积更小。我们不会导出组件,然后也会为其提供 render props – 您只需渲染它。

另一个目标是开始将 UI 与编辑器分离。我们希望核心在没有 React 的情况下可用,因此,更清晰地描绘 UI 并将其与编辑器配置和逻辑分离是有意义的。

但是,使用 children 并不是没有权衡,所以让我们来看一下这些新 API 的变化,解释一下它是如何在幕后工作的,以及对您的应用程序的影响。

<Footer/>

以下是编辑器中页脚的外观:

我们有默认的页脚 UI,您当前无法更改。中间有一个区域是可以渲染的。之前,您会使用 renderFooter props 来执行此操作。现在,您将从我们的包中导入Footer 组件,并将其呈现为 Excalidraw 组件的子组件,以及您需要的任何 UI。

import { Excalidraw, Footer } from "@excalidraw/excalidraw";

const App = () => (<Excalidraw><Footer><button onClick={() => console.log("Clicked!")}>Click me</button></Footer></Excalidraw>
); 

那么这到底是如何运作的呢?我们如何知道哪些是 Footer 子组件,哪些是不相关的组件,并如何将其渲染到 UI 中适当位置时?

为此,我们决定使用一个更老的 React API,现在被认为是已过时的 API:React.Children。但它能够很好的解决一些问题,所以我们继续使用它:)。

简而言之,我们通过循环将子组件传递给 Excalidraw,并使用它们的displayName 筛选出我们要查找的组件。下面是简化代码的样子:

export const getReactChildren = <ExpectedChildren extends {[k in string]?: React.ReactNode;}
>( children: React.ReactNode, ) => {return React.Children.toArray(children).reduce((acc: Partial<ExpectedChildren>, child) => {if (React.isValidElement(child)) {acc[child.type.displayName] = child;}return acc;},{},);
}; 

在实践中,我们还根据预期对子组件的名称进行验证,然后对这些组件进行渲染。这么做的好处是,它允许您将所有 UI 组件作为子组件进行渲染,而不考虑顺序,由我们来判断在何处渲染。

但它也有一些缺点。首先,您必须将组件渲染为 Excalidraw 组件的顶级子组件。这不是什么大问题,但这确实意味着不能将 Footer 组件渲染为另一个组件的子组件,否则我们将无法找到它:

const MyFooter = () => {return <Footer />;
};

const App = () => (<Excalidraw>{/* nope :( */}<MyFooter /></Excalidraw>
); 

让我们继续介绍下一个组件。

<MainMenu/>

在新的编辑器设计中引入了左上角的下拉菜单,我们希望您能够根据自己的需要对其进行自定义。

下面是 excalidraw.com 上的菜单(左),以及我们在包中默认呈现的菜单(右)。

但是,我们保证了最大程度上的灵活性。如果默认项不适合您,您可以自己渲染MainMenu 组件,我们将允许您从头开始构建它 – 使用默认菜单项组件或您自己的组件。

import { Excalidraw, MainMenu } from "@excalidraw/excalidraw";

const App = () => (return (<Excalidraw><MainMenu><MainMenu.DefaultItems.LoadScene /><MainMenu.DefaultItems.Export /><MainMenu.DefaultItems.SaveAsImage /><MainMenu.Separator /><MainMenu.Item onSelect={() => alert("Hello to you too!")}>Hello!</MainMenu.Item></MainMenu></Excalidraw>);
); 

与 Footer 一样,您需要确保它是 Excalidraw 组件的顶级子组件。

<WelcomeScreen/>

我们在重新设计中引入的另一个东西是欢迎页。这是一个稍微复杂一些的组件,因为它由几个单独的元素组成,每个元素在 UI 的不同位置上渲染。

两个最主要的组件是包含 logo 和快速操作的中心部分,以及指出用户可以在 UI 中找到什么的提示。

您可以对其中的大部分内容进行自定义。你可以只渲染中心部分,也可以改变一下提示。

值得注意的是,我们不仅要求 是顶级子组件,而且还要求 <WelkeScreen.Center/> 和 <WelcomeScreen.Hints/> 是 的直接子组件。

import { Excalidraw, WelcomeScreen } from "@excalidraw/excalidraw";

const App = () => (return (<Excalidraw><WelcomeScreen><WelcomeScreen.Hints.ToolbarHint /><WelcomeScreen.Center><WelcomeScreen.Center.Logo /><WelcomeScreen.Center.Heading>You can draw anything you want!</WelcomeScreen.Center.Heading><WelcomeScreen.Center.Menu><WelcomeScreen.Center.MenuItemHelp /><WelcomeScreen.Center.MenuItemLiveCollaborationTriggeronSelect={() => setCollabDialogShown(true)}/>{!isExcalidrawPlusSignedUser && (<WelcomeScreen.Center.MenuItemonSelect={() => console.log("doing something!")}>Do something</WelcomeScreen.Center.MenuItem>)}</WelcomeScreen.Center.Menu></WelcomeScreen.Center></WelcomeScreen></Excalidraw>);
); 

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

<think>好的,用户想做一个关于Web应用移动APP系统架构图的PPT,其中Web端使用Vue.jsJava前后端分离,移动端用uni-app调用同一个Java后端API。我需要先理解用户的具体需求,然后给出如何组织PPT内容的建议。 首先,用户的需求是展示整个系统的架构设计,涵盖Web移动端,并且要体现它们如何与后端交互。可能用户需要的是结构清晰、重点突出、视觉化的PPT,适合向技术团队或管理层展示。 接下来,我需要参考提供的引用内容。引用1提到Uni-app的跨平台特性,可以简化开发维护,同时前端使用Vue.js。引用34展示了Java后端如何与前端交互,尤其是引用4中的登录流程,可能对架构图中的数据流动部分有帮助。引用2比较了微信小程序的加载方式,但可能当前问题关联不大,但其中提到的视图层逻辑层分离或许在架构设计中有参考价值。 用户需要制作架构图,所以PPT的结构应该分模块介绍各个部分。可能需要包括整体架构图、前端结构(Web移动端)、后端结构、数据交互流程、技术选型优势等部分。每个部分需要简明扼要,配合图示关键点说明。 考虑到用户的技术栈是Web前端Vue.js,后端Java,移动端uni-app,需要强调前后端分离的好处,以及uni-app如何复用代码调用同一API。可能还需要说明数据库的选择,比如引用3提到的MySQL,但用户的问题中没有明确提到,可能需要确认。 另外,用户可能需要知道如何绘制这些架构图,比如使用工具(如Draw.io、Visio)、颜色搭配、模块分层等设计建议。同时,PPT的内容结构需要逻辑清晰,从整体到局部,逐步展开。 可能用户没有提到的点包括安全性、性能优化、部署架构等,但根据问题描述,可能不需要深入这些细节,除非架构图需要展示。需要保持回答聚焦在用户的需求上,即如何组织PPT内容来展示架构设计。 最后,生成相关问题时要围绕系统架构设计、技术选型理由、开发工具、跨平台优势等方面,帮助用户进一步深入思考或解决可能遇到的问题。</think>### 分步回答:如何创建展示Web与移动端架构设计的PPT #### 一、**明确PPT核心模块** 1. **整体架构图设计** - 绘制**分层架构图**,体现前端(Web+移动端)与后端分离特性 - 示例结构: ``` ┌───────────────┐ HTTP/HTTPS ┌───────────────┐ │ Web前端 │◀──── API请求 ──────▶│ Java后端 │ │ (Vue.js) │ │ (Spring Boot) │ └───────┬───────┘ └───────┬───────┘ │ │ ┌───────▼───────┐ ┌───────▼───────┐ │ 移动端 │ │ 数据库/中间件 │ │ (uni-app) │ │ (MySQL/Redis) │ └───────────────┘ └───────────────┘ ``` - 标注关键通信方式:RESTful API、WebSocket、Token鉴权等[^4] 2. **技术栈对比与优势** - **Web前端**:Vue.js的组件化开发、响应式数据绑定 - **移动端**:uni-app"一次开发多端发布"特性(iOS/Android/小程序)[^1] - **后端**:Java的高并发处理能力(如Spring Cloud微服务架构) #### 二、**分模块详解设计** 1. **Web端架构** - 使用**泳道图**展示前后端交互流程: ```mermaid graph LR A[Vue组件] -->|Axios请求| B[Vue Router] B --> C[Vuex状态管理] C -->|API调用| D[Java Controller] D -->|MyBatis| E[MySQL数据库] ``` - 强调关键点: - 前端工程化(Webpack/Vite打包) - 接口文档管理(Swagger/YApi) 2. **移动端架构** - 展示uni-app**跨端原理**: ``` ┌──────────┐ 编译转换 ┌──────────┐ │ Vue语法 ├───▶ 平台特定代码 ──▶ iOS/Android │ └──────────┘ (uni-app) └──────────┘ ``` - 标注核心能力: - 本地存储(用户设置/缓存) - 设备API调用(摄像头、GPS)[^3] 3. **共享后端设计** - 用**时序图**说明统一API调用流程[^4]: ```mermaid sequenceDiagram Web前端->>+Java后端: GET /api/data uni-app->>+Java后端: GET /api/data Java后端-->>-Web前端: JSON响应 Java后端-->>-uni-app: JSON响应 ``` #### 三、**视觉设计建议** 1. **配色方案** - 前端(蓝色系)+ 后端(绿色系)+ 移动端(紫色系)区分模块 - 使用**渐变色箭头**表示数据流向 2. **工具推荐** - 架构图绘制:Draw.io(在线免费)、Excalidraw(手绘风格) - 流程图/时序图:Mermaid语法(Markdown兼容) - 图标资源:Iconfont(阿里矢量图标库) 3. **动画设计** - 分步骤展示架构层级(如先显示后端,再展开前端连接) - 对关键路径添加高亮闪烁效果 #### 四、**典型内容页示例** 1. **技术选型对比页** | 模块 | 技术方案 | 优势说明 | |------------|-------------|--------------------------| | Web前端 | Vue 3 | 响应式编程+组合式API | | 移动端 | uni-app | 跨端开发+微信生态兼容 | | 后端框架 | Spring Boot | 快速集成安全/监控组件 | 2. **性能优化页** - Web端:CDN静态资源分发 + 路由懒加载 - 移动端:图片压缩 + 本地缓存策略[^2] - 后端:Redis缓存热点数据 + Nginx负载均衡
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值