资讯动态

gpui-kit 无样式 Accordion 原语:基于 GPUI Base 构建可访问、可控状态的折叠面板组件

发布时间:2026/9/15 12:46:31 来源:尧图企业网站定制
gpui-kit 无样式 Accordion 原语基于 GPUI Base 构建可访问、可控状态的折叠面板组件【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit导读Accordion折叠面板是桌面应用中组织内容、节省纵向空间的常见交互组件。gpui-kit 的 Base 层为它提供了一套只负责行为与语义、不规定任何视觉的无样式原语unstyled primitives由Accordion、AccordionItem、AccordionHeader、AccordionTrigger、AccordionPanel五个公开类型组合而成。本文将基于 website/zh-CN/base/primitives/accordion.md 文档结合 crates/base/src/accordion.rs 源码与 showcase 示例讲解如何导入、组合、受控管理状态并打通键盘操作与无障碍语义让你能在自己的设计系统中直接复刻这套折叠面板。设计定位行为与语义分离视觉完全交给应用GPUI Base 原语的设计哲学是组件只提供行为结构和语义结构不内置任何产品视觉语言。这一点在 Accordion 上体现得尤为彻底——源码文档注释开宗明义地写着 An unstyled accordion root for application-owned items一个无样式、应用自持条目的折叠根节点见 crates/base/src/accordion.rs。落到实践中意味着标题、触发器的外观字号、颜色、边框、图标、悬停态全部由你的样式代码决定展开/收起动画、图标旋转、间距等视觉细节由应用层实现Base 层只负责受控展开状态、点击回调、aria-expanded等无障碍状态、标题与区域的语义角色、面板的条件挂载。因此文档强调请使用 GPUI 样式Styledtrait 提供的一系列方法并组合导出的部件使其符合你的设计系统。导入与运行示例导入公开类型use gpui_kit::base::{Accordion, AccordionHeader, AccordionItem, AccordionPanel, AccordionTrigger};这五个类型从crates/base/src/lib.rs的pub use accordion::{...}统一导出见 crates/base/src/lib.rs。运行原生示例Accordion 的示例位于 showcase 组件集中原生与 WASM 预览共用同一份实现同一文件被两条构建路径引用。本地运行cargo run -p gpui-base-examples -- accordion这条命令对应的二进制是 crates/base/examples/native/src/bin/components.rs它把命令行第一个参数作为要展示的组件名传给showcase::run包名定义在 crates/base/examples/native/Cargo.tomlname gpui-base-examples默认运行components这个 bin。Accordion 被注册在 showcase 的组件清单中crates/base/examples/showcase/mod.rs并在页面渲染的分发逻辑中映射为self.accordion(cx)见 crates/base/examples/showcase/mod.rs。启动后会打开一个居中窗口左侧目录里选择 accordion 即可看到示例页如果只输入cargo run -p gpui-base-examples不传参数则默认进入overview概览页。结构模型五个部件各司其职从源码的类型设计crates/base/src/accordion.rs可以清晰梳理出五层结构类型职责关键方法Accordion折叠组根节点容器角色new(id)实现Styled/ParentElement/InteractiveElement渲染为Role::GroupAccordionItem一个触发器 面板的条目open(bool)、disabled(bool)、header(...)、panel(...)AccordionHeader标题容器拥有触发器new(trigger)、level(usize)、id(...)渲染为Role::Heading并带aria_levelAccordionTrigger可点击、可聚焦的开关new(id)、open(bool)、disabled(bool)、on_change(...)渲染为Role::Button并投影aria-expandedAccordionPanel展开时挂载的内容区open(bool)、keep_mounted(bool)、id(...)渲染为Role::Region几个值得注意的实现细节根节点与触发器是有状态元素。Accordion和AccordionTrigger内部都包裹了ObservedElementgpui::StatefulDiv因此可以响应点击、跟踪焦点track_focus并且配合test_support()获得测试辅助能力。Header 默认标题级别为 3。AccordionHeader::new的默认level是3crates/base/src/accordion.rs可用.level(2)等按文档大纲需求调整最终通过aria_level暴露给辅助技术。Trigger 激活语义是请求相反状态。源码中let next_open !self.open;crates/base/src/accordion.rs即点击时把当前状态取反作为请求结果交给on_change实际是否更新由应用决定——这正是受控组件的标志。Panel 支持条件挂载。默认keep_mounted false当!open !keep_mounted时渲染为gpui::Empty完全不进入元素树见 crates/base/src/accordion.rs如果你希望面板内容在关闭时仍保留在树中例如为了缓存滚动位置或做展开动画用.keep_mounted(true)。状态与事件受控模式是唯一推荐路径文档明确指出受控状态应保存在父渲染类型或 GPUI entity 中。每次触发器的on_change回调收到下一次展开状态后应用在回调中更新自己的状态字段并调用cx.notify()触发重渲染不要在渲染函数里每次重建持久 entity——那会丢失焦点与内部状态。从示例 crates/base/examples/showcase/components/accordion.rs 可以看到完整的受控闭环let open self.accordion_items[index]; let entity cx.entity().downgrade(); AccordionItem::new() .open(open) .header(AccordionHeader::new( AccordionTrigger::new(format!(accordion-trigger-{index})) .on_change(move |next, _, _, cx| { _ entity.update(cx, |this, cx| { this.accordion_items[index] next; cx.notify(); }); }) // ... 样式链 )) .panel(AccordionPanel::new() /* ... */ .child(answer))状态字段accordion_items: [bool; 3]定义在 showcase 结构体里crates/base/examples/showcase/mod.rs初始值为[true, false, false]第一个面板默认展开见 crates/base/examples/showcase/mod.rs。关键点on_change的签名是Fn(bool, ClickEvent, mut Window, mut App)第一个bool即请求的下一状态源码见 crates/base/src/accordion.rs回调里通过entity.update写回父级状态并cx.notify()用cx.entity().downgrade()捕获弱引用避免回调持有父实体造成引用环由于open是受控的AccordionTrigger和AccordionPanel接收到的open永远来自应用状态渲染结果与状态一致。样式组合触发器与面板的完整示例链示例展示了如何在不触碰语义结构的前提下用 GPUI 样式方法把原语装修成可用的 UI完整源码见 crates/base/examples/showcase/components/accordion.rsAccordion::new(example-accordion) .w(px(270.)) .border_t_1() .border_color(example_rgb(0xd4d4d4)) .children( items.into_iter().enumerate().map(|(index, (question, answer))| { let open self.accordion_items[index]; // ... AccordionItem::new() .open(open) .header(AccordionHeader::new( AccordionTrigger::new(format!(accordion-trigger-{index})) .on_change(...) .w_full().flex().items_center().justify_between() .h_7().border_b_1().border_color(example_rgb(0xd4d4d4)) .text_xs() .child(question) .child(div().text_color(example_rgb(0x737373)) .child(if open { − } else { })), )) .panel( AccordionPanel::new() .px_1().py_1().border_b_1() .border_color(example_rgb(0xd4d4d4)) .text_xs().text_color(example_rgb(0x525252)) .child(answer), ) }), )这段代码传达了几个可复用的模式Root 用稳定 Element IDAccordion::new(example-accordion)、AccordionTrigger::new(accordion-trigger-{index})。文档注意事项特别提醒在支持的位置使用稳定元素 ID这在测试、焦点管理和无障碍树里都依赖它。展开指示符由应用绘制示例用文本−/表达展开/收起你完全可以用图标组件替换——这正是视觉属于应用的体现。Trigger 自己决定布局flexjustify_between让标题文本与指示符分居两端h_7控制行高均为 GPUIStyled方法。Panel 通过.open(open)同步受控状态关闭时该面板直接从元素树卸载未启用keep_mounted时。键盘操作与可访问性文档对 Accordion 的可访问性要求可以总结为三点触发器可聚焦、可用键盘操作、向辅助技术暴露展开状态。对照源码这三点的实现依据是可聚焦AccordionTrigger实现InteractiveElement并提供track_focus(handle)crates/base/src/accordion.rs应用可把FocusHandle绑定到触发器上纳入焦点管理。键盘操作触发器渲染为Role::Button天然继承 GPUI 对按钮的键盘激活语义空格/回车触发点击。暴露展开状态渲染时aria_expanded(self.open)直接把受控的open状态写入无障碍树crates/base/src/accordion.rs。结构语义同样完整AccordionHeader以Role::Headingaria_level暴露标题层级crates/base/src/accordion.rsAccordionPanel以Role::Region暴露内容区crates/base/src/accordion.rs根节点以Role::Group组织整组crates/base/src/accordion.rs。这些语义有单元测试背书。在 crates/base/src/accordion.rs 的tests模块中trigger_projects_expanded_accessibility_state断言触发器无障碍节点角色为Button且is_expanded() Some(true)同时确认仅渲染不点击不会触发on_changepointer_requests_next_controlled_state_and_respects_disabled通过simulate_click验证点击openfalse的触发器会请求true而disabledtrue的触发器点击后不会产生任何请求——即禁用状态在 Base 层就被拦截header_and_panel_project_structural_roles验证 Header 与 Panel 分别投影Heading与Region角色。注意事项与消费端验收清单文档最后给出两条工程化建议结合源码可以做更具体的落地使用稳定元素 ID。Accordion、AccordionTrigger、以及可选的AccordionHeader::id(...)、AccordionPanel::id(...)都接受ElementId。稳定的 ID 让 GPUI 的元素差异比对diffing在重渲染时保持一致避免焦点与动画状态漂移。在消费端设计系统中验证完整状态矩阵。由于 Base 层不提供视觉你需要自行确认以下状态在你的主题下都成立悬停hover、按下active、聚焦focus与聚焦可见focus-visible的样式差异选中/展开态的视觉反馈禁用disabled(true)态的弱化样式——注意禁用逻辑在 Base 层已实现点击不会产生变更请求但视觉反馈需要你画prefers-reduced-motion减少动态效果下的降级尤其是如果你用keep_mounted(true)配合展开动画时高对比度high contrast主题下的边框与文本可读性。总结gpui-kit 的 Base Accordion 是一组把交互逻辑与视觉呈现完全解耦的原语受控的open状态、请求式的on_change回调、aria-expanded/Heading/Region/Group语义角色、可选的keep_mounted挂载策略以及开箱即用的禁用拦截全部在 crates/base/src/accordion.rs 这一个文件里实现完毕。你要做的只是导入五个类型、把状态放进自己的 entity、再用 GPUI 样式画出你的设计语言。文档原文与可运行示例位于 website/zh-CN/base/primitives/accordion.md 和 crates/base/examples/showcase/components/accordion.rs动手跑一遍cargo run -p gpui-base-examples -- accordion即可获得最直观的感受。【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价