ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Golden Layout 组件绑定机制完全指南:Embedding 与 Virtual 两种模式、四种绑定方式深度解析

Golden Layout 组件绑定机制完全指南:Embedding 与 Virtual 两种模式、四种绑定方式深度解析 前端UI组件【免费下载链接】golden-layoutA multi window layout manager for webapps项目地址https://gitcode.com/gh_mirrors/go/golden-layout点击查看免费下载导读本文聚焦 Golden Layout多窗口布局管理器最核心的机制——组件绑定Binding Components。Golden Layout 并不直接渲染业务组件而是通过绑定将应用组件纳入布局系统并接管其位置position、尺寸size与可见性visibility。文档 docs/binding-components/index.md 系统阐述了四种绑定方式Embedding via Registration经典注册式、Embedding via Events事件式嵌入、Virtual via Registration注册式虚拟化、Virtual via Events纯事件虚拟组件。读完本文你将掌握每种方式的适用场景、完整事件签名与可运行代码示例并理解底层 virtual-layout.ts、golden-layout.ts、component-container.ts 的实现原理能够在自己的应用中正确选型并落地。一、绑定概述Golden Layout 如何控制你的组件Golden Layout 将自身定位为一个布局引擎它负责决定每个组件该出现在哪里、占多大面积、是否可见而组件本身的创建与销毁则交由应用决定。绑定Binding就是二者之间的契约。根据绑定方式的不同组件根元素在 DOM 层级中的归属有两种截然不同的策略嵌入模式Embedding组件根 HTML 元素被插入到 Golden Layout 自身的 DOM 子树中。布局变化时组件根元素的祖先节点可能被重新挂载reparented。虚拟模式Virtual组件根元素不进入Golden Layout 的 DOM 子树而是由应用自行管理。布局变化时组件元素不会被 reparentGolden Layout 仅通过事件通知应用应如何摆放组件。文档定义了四种绑定方式下文逐一展开。二、Embedding via Registration经典注册式绑定这是 Golden Layout 最早也最常用的绑定方式。应用把组件的构造函数或工厂函数注册到布局中当布局需要某个组件的新实例时Golden Layout 负责实例化实例化时Golden Layout 传入一个ComponentContainer对象其中包含一个 HTML 元素container.element构造函数/工厂函数创建组件对象并把组件顶层 HTML 元素挂为container.element的子节点此后组件即成为 Golden Layout DOM 层级的一部分布局重排时祖先节点会相应地被 reparent。可用的注册函数文档列出了五个注册入口全部定义在 golden-layout.ts注册函数说明GoldenLayout.registerComponent()通用入口根据传入函数是否拥有prototype属性自动分派到构造函数或工厂函数见 golden-layout.ts已标记 deprecatedGoldenLayout.registerComponentConstructor()注册构造函数new方式实例化GoldenLayout.registerComponentFactoryFunction()注册工厂函数以函数调用方式实例化GoldenLayout.registerComponentFunction()注册根据 config 返回构造函数的回调已标记 deprecated建议改用下一条GoldenLayout.registerGetComponentConstructorCallback()注册回调在组件类型未注册时按需提供构造函数从源码看注册的组件类型存放在_componentTypesMap中注册信息包含constructor、factoryFunction与virtual三个字段golden-layout.ts。构造函数与工厂函数的签名分别为type ComponentConstructor new(container: ComponentContainer, state: JsonValue | undefined, virtual: boolean) ComponentContainer.Component; type ComponentFactoryFunction (container: ComponentContainer, state: JsonValue | undefined, virtual: boolean) ComponentContainer.Component | undefined;注意同一类型名重复注册会抛出BindErrorComponent is already registered源码见 golden-layout.ts。组件构造函数的典型形态以仓库 apitest 示例中的 text-component.ts 为参照一个经典的嵌入组件构造如下接收container、state、virtual三个参数并将自身元素挂入container.elementclass TextComponent { constructor(container: ComponentContainer, state: JsonValue | undefined, virtual: boolean) { // 非 virtual 模式下rootElement 即 container.element const rootElement container.element; // ...创建业务 DOM、绑定事件 } }在 component-base.ts 中可以看到两种模式的根元素策略virtual false时_rootElement this._container.element嵌入到容器内virtual true时则新建一个position: absolute; overflow: hidden的 div虚拟模式独立挂载。三、Embedding via Events事件式嵌入当应用希望对组件分配拥有更强控制权时可以不注册而改用事件。只要给VirtualLayout.bindComponentEvent事件挂上处理器每当需要新组件时该事件即被触发。处理器需要创建或获取组件确保组件顶层 HTML 元素成为container.element的子节点以BindableComponent接口返回组件且virtual: false。组件从布局中移除时需要把组件顶层元素从container.element中移除其他拆除tear-down动作同样在此阶段完成。文档给出两个时机二者都会在组件不再被需要时触发若已挂处理器VirtualLayout.unbindComponentEvent事件组件容器的beforeComponentRelease事件从 component-container.ts 可知releaseComponent()会先 emitbeforeComponentRelease再调用layoutManager.unbindComponent()。事件绑定在 apitest 中的实现apitest/app.ts 给出了完整范例handleBindComponentEvent中通过_useVirtualEventBinding开关决定返回virtual: true还是virtual: false。嵌入模式下的解绑注释明确写道If embedded, then component handles unbinding of component elements from content.element——即嵌入模式下组件自己负责元素清理。四、Virtual via Events纯事件虚拟组件Virtual Components这是版本 2 引入、控制力最强的方式。虚拟模式下 Golden Layout完全不知道组件内部结构组件 HTML 元素也不在其 DOM 层级中。布局引擎只负责计算通过事件把需要的位置、尺寸、可见性、z-index告知应用由应用自行应用这些值。文档用虚拟表格virtual grids作类比网格不包含展示内容而是通过事件请求内容。虚拟组件的四大优势布局变化时组件及其祖先不会被 reparent从而避免破坏 iframe、WebSocket 等对 DOM 挂载位置敏感的资源无需再从组件中抽取顶层 HTML 元素在注册式嵌入中这一步往往很别扭对 Angular、Vue 等自带组件层级的框架友好无需为了插入 Golden Layout 而打破框架的父子关系规范组件元素的传送teleporting不再是必须的调试更轻松应用组件直接挂在 Golden Layout 根元素下应用相关的 DOM 层级明显更浅。需要处理的全部事件含源码级实现对照1.VirtualLayout.bindComponentEvent: (container, itemConfig) ComponentContainer.BindableComponent每当 Golden Layout 需要绑定新组件时触发。处理器接收container与组件条目解析后的配置itemConfig典型流程用itemConfig创建或获取组件取得组件顶层 HTML 元素确保该元素position: absolute把元素挂到 Golden Layout 根 HTML 元素下以container为键把组件存入 map给 container 挂上virtualRectingRequiredEvent与virtualVisibilityChangeRequiredEvent以及可选的virtualZIndexChangeRequiredEvent处理器返回{ component, virtual: true }形式的BindableComponent。文档示例可在 apitest/app.ts 找到几乎一致的真实实现private handleBindComponentEvent(container: ComponentContainer, itemConfig: ResolvedComponentItemConfig) { const componentTypeName ResolvedComponentItemConfig.resolveComponentTypeName(itemConfig); if (componentTypeName undefined) { throw new Error(handleBindComponentEvent: Undefined componentTypeName); } const component this.createVirtualComponent(container, componentTypeName, itemConfig.componentState); const componentRootElement component.rootHtmlElement; this._layoutElement.appendChild(componentRootElement); this._boundComponentMap.set(container, component); container.virtualRectingRequiredEvent (container, width, height) this.handleContainerVirtualRectingRequiredEvent(container, width, height); container.virtualVisibilityChangeRequiredEvent (container, visible) this.handleContainerVisibilityChangeRequiredEvent(container, visible); return { component, virtual: true, }; }resolveComponentTypeName的实现位于 resolved-config.ts仅当itemConfig.componentType为字符串时才返回类型名否则返回undefined。2.VirtualLayout.unbindComponentEvent: (container) void组件从布局中移除时触发。处理器以container为键在 map 中找到组件将其从 Golden Layout 根元素下移除并从 map 中删除private handleUnbindComponentEvent(container: ComponentContainer) { const component this._boundComponentMap.get(container); if (component undefined) { throw new Error(handleUnbindComponentEvent: Component not found); } const componentRootElement component.rootHtmlElement; if (componentRootElement undefined) { throw new Error(handleUnbindComponentEvent: Component does not have a root HTML element); } this._layoutElement.removeChild(componentRootElement); this._boundComponentMap.delete(container); }从 virtual-layout.ts 可以看到底层分发逻辑若unbindComponentEvent存在则调用之否则在非 virtual 模式下回退到已废弃的releaseComponentEvent。3.LayoutManager.beforeVirtualRectingEvent: () void该事件不必处理但可用于优化定位性能。一次布局变化可能伴随多个组件需要重排此事件在一次布局变化引发的一批定位开始前触发一次。典型用法调用 Golden Layout 根元素的getBoundingClientRect()并缓存供后续每个组件的定位计算复用private handleBeforeVirtualRectingEvent(count: number) { this._goldenLayoutBoundingClientRect this._layoutElement.getBoundingClientRect(); }底层支撑可见 layout-manager.tsendVirtualSizedContainerAdding()会批量收集需要重排的虚拟容器先fireBeforeVirtualRectingEvent(count)再逐个notifyVirtualRectingRequired()最后fireAfterVirtualRectingEvent()。此外还有一个对偶的afterVirtualRectingEvent钩子layout-manager.ts。4.ComponentContainer.virtualRectingRequiredEvent: (container, width, height) void组件的位置与/或尺寸需要改变时触发。处理器以container为键查组件然后获取 Golden Layout 根元素的位置getBoundingClientRect()也可复用beforeVirtualRectingEvent中缓存的结果获取 container 自身位置getBoundingClientRect()计算 container 相对 Golden Layout 根元素的位置偏移更新组件顶层元素的left、top、width、height。private handleContainerVirtualRectingRequiredEvent(container: ComponentContainer, width: number, height: number) { const component this._boundComponentMap.get(container); if (component undefined) { throw new Error(handleContainerVirtualRectingRequiredEvent: Component not found); } const rootElement component.rootHtmlElement; if (rootElement undefined) { throw new Error(handleContainerVirtualRectingRequiredEvent: Component does not have a root HTML element); } const containerBoundingClientRect container.element.getBoundingClientRect(); const left containerBoundingClientRect.left - this._goldenLayoutBoundingClientRect.left; rootElement.style.left this.numberToPixels(left); const top containerBoundingClientRect.top - this._goldenLayoutBoundingClientRect.top; rootElement.style.top this.numberToPixels(top); rootElement.style.width this.numberToPixels(width); rootElement.style.height this.numberToPixels(height); }numberToPixels在 utils/utils.ts 中实现即value px。事件触发时机可由 component-container.ts 的setSizeToNodeSize()/notifyVirtualRectingRequired()佐证。5.ComponentContainer.virtualVisibilityChangeRequiredEvent: (container, visible) void组件可见性变化时触发通过display属性切换private handleContainerVisibilityChangeRequiredEvent(container: ComponentContainer, visible: boolean) { const component this._boundComponentMap.get(container); // ...查表与判空 if (visible) { componentRootElement.style.display ; } else { componentRootElement.style.display none; } }Golden Layout 内置的注册式虚拟绑定也使用同样的工具函数setElementDisplayVisibilityutils/utils.ts。6.ComponentContainer.virtualZIndexChangeRequiredEvent: (container, logicalZIndex, defaultZIndex) void组件的 z-index 需要变化时触发。处理器应将组件 z-index 设为参数defaultZIndexprivate handleContainerVirtualZIndexChangeRequiredEvent(container: ComponentContainer, logicalZIndex: LogicalZIndex, defaultZIndex: string) { // ...查表与判空 componentRootElement.style.zIndex defaultZIndex; }logicalZIndex的取值范围在 utils/types.ts 中定义base | drag | stackMaximiseddefaultZIndex由LogicalZIndexToDefaultMap映射为具体 CSS 值对应StyleConstants中的默认 z-index 常量。在 component-container.ts 中setLogicalZIndex()会在此值变化时调用notifyVirtualZIndexChangeRequired()触发该事件——例如组件进入拖拽LogicalZIndex.drag或 stack 最大化LogicalZIndex.stackMaximised状态时。关于 apitest 的实践提示文档明确指出apitest 应用演示了虚拟组件的完整实现见 apitest/app.ts 与 apitest/component-base.ts。在 apitest 中App构造函数通过new GoldenLayout(layoutElement, bindHandler, unbindHandler)注入事件处理器并设置beforeVirtualRectingEvent缓存布局根元素位置ComponentBase实现了GoldenLayout.VirtuableComponent接口提供rootHtmlElementgetter并在虚拟模式下将根元素设为absoluteoverflow: hidden。虚拟模式的定位思维使用虚拟组件时请把 Golden Layout 当作一个计算位置的引擎而非实际摆放组件的容器。这种绑定方式初始化成本更高但换来了更大的灵活性任意 HTML 元素都可作为组件的父容器不限于 Golden Layout 容器不同组件可以拥有不同的父容器从而继承不同的 CSS 或采用不同的事件传播处理方式。五、Virtual via Registration注册式虚拟化混合模式上面的六个事件给了应用极大灵活性但集成成本也高。如果只想低成本获得虚拟组件的收益可以采用注册式虚拟化组件仍然像经典方式一样注册但注册时打上virtual: true标记Golden Layout 内部便会按虚拟组件方式处理它并在内部自行管理那些事件——应用无需编写任何事件处理器。迁移四步法对既有应用几乎零侵入文档给出了从经典注册升级到虚拟注册的四个步骤注册函数新增virtual参数默认false经典嵌入绑定设为true表示该类型组件在内部以虚拟组件方式实现。该参数在 golden-layout.ts 与 golden-layout.ts 的registerComponentConstructor/registerComponentFactoryFunction签名中均可确认。组件提供rootHtmlElementgetterTypeScript 组件应实现GoldenLayout.VirtuableComponent接口。接口定义见 golden-layout.ts仅要求rootHtmlElement: HTMLElement。根元素的overflowCSS 属性须设为hidden。确保 Golden Layout 容器 HTML 元素处于定位状态即其position属性非static。注册式虚拟绑定的底层行为源码佐证在 golden-layout.ts 的bindComponent()中可以看到注册式虚拟化的完整内部流程从注册表取到instantiator后以其virtual标记判断走虚拟路径虚拟路径下实例化组件后将其强转为VirtuableComponent取rootHtmlElement调用ensureElementPositionAbsolute(rootElement)见 utils/utils.ts强制设置position: absolute把根元素appendChild到 Golden Layout 容器下登记到_virtuableComponentMap内部自动挂上virtualRectingRequiredEvent、virtualVisibilityChangeRequiredEvent、virtualZIndexChangeRequiredEvent三个处理器处理器实现位于 golden-layout.ts与文档中事件式虚拟组件的手写处理器逻辑完全一致相对getBoundingClientRect()偏移定位、display切换、zIndex赋值。解绑路径同样在内部处理unbindComponent()golden-layout.ts会从容器移除根元素并清理_virtuableComponentMap。需要注意的三处行为差异文档明确提醒迁移后会有少量行为变化Golden Layout 会确保组件根元素为absolute定位Golden Layout 会直接修改根元素的高度与宽度。嵌入绑定修改的是容器元素而非组件根元素的尺寸——如果你的应用自己也设置了组件根元素的高宽需要调整设计。简便做法给当前根元素套一个新父元素让新父元素成为组件的根元素业务逻辑继续使用原元素Golden Layout 操作新根元素Golden Layout 会修改组件根元素的 z-index。一个限制virtual via registration绑定不支持GoldenLayout.registerGetComponentConstructorCallback()注册函数。六、多绑定方式共存绑定顺序与优先级应用可以针对不同组件类型混用多种绑定方式。每当需要绑定组件时Golden Layout 按下述顺序尝试见 golden-layout.ts 与 virtual-layout.ts 的分发逻辑先查注册表若该类型已注册则按注册信息绑定含注册式虚拟化再查bindComponentEvent处理器若存在以事件方式绑定为虚拟组件再查getComponentEvent处理器若存在以事件方式将组件静态嵌入 Golden Layout DOM该方法已废弃以上皆无则抛出异常BindErrorComponentTypeNotRegisteredAndBindComponentEventHandlerNotAssigned。当同时使用 Virtual via Events 与 Embedding via Events 时unbindComponentEvent处理器可以通过ComponentContainer.virtual字段component-container.ts判断某个组件究竟采用了哪种绑定方式从而决定解绑动作apitest 中 app.ts 正是这样做的container.virtual为 true 时才从布局根元素移除嵌入模式交由组件自行清理。七、VirtualLayout 类无注册功能的轻量布局Golden Layout 的继承层级为LayoutManager→VirtualLayout→GoldenLayout源码分别在 layout-manager.ts、virtual-layout.ts、golden-layout.ts。VirtualLayout实现了 Golden Layout 除注册函数外的全部功能。如果应用只打算用bindComponentEvent做纯虚拟组件可以直接创建VirtualLayout实例无需引入GoldenLayout。这一设计意味着纯事件驱动的应用可以完全绕开注册表与_componentTypesMap。此外VirtualLayout构造函数还支持把bindComponentEvent/unbindComponentEvent处理器作为第二、第三参数直接传入virtual-layout.ts此时构造流程是确定性的determinate即使是为 popout 子窗口创建实例也会立即调用init()处理器须随时就绪。getComponentEvent与releaseComponentEvent两个旧事件在VirtualLayout上保留但已标记 deprecated官方建议改用bindComponentEvent/unbindComponentEvent配合虚拟组件virtual-layout.ts。八、选型场景速查表场景推荐绑定方式理由快速上手Embedding via Registration经典用法注册即用文档与示例最丰富既有应用兼容Embedding via Registration现有注册代码零改动自动沿用经典绑定消除getComponentEvent弃用警告Embedding via Events以bindComponentEventvirtual: false快速替换低成本获得虚拟化收益Virtual via Registration注册时virtual: true仅需实现rootHtmlElement并做少量 CSS/定位调整最大设计自由度Virtual via Events完全掌控组件创建、销毁与定位支持自定义父容器与多父容器架构结语四种绑定方式的本质差异在于组件根元素归属权与定位职责的分配Embedding 把组件收编进布局 DOM 子树由 Golden Layout 直接摆布Virtual 则把组件留在应用侧Golden Layout 退化为纯计算引擎通过bindComponentEvent、unbindComponentEvent、virtualRectingRequiredEvent、virtualVisibilityChangeRequiredEvent、virtualZIndexChangeRequiredEvent、beforeVirtualRectingEvent六个事件与ComponentContainer.BindableComponent契约完成协作。对 iframe/WebSocket 敏感、Angular/Vue 等框架应用而言虚拟模式能显著降低布局变化带来的 DOM 重挂载风险是版本 2 起最值得采用的绑定策略而注册式虚拟化则为存量应用提供了一条近乎无痛的升级路径。实践时可直接对照仓库 apitest 的可运行示例并深入阅读 virtual-layout.ts、golden-layout.ts 与 component-container.ts 三个核心文件验证行为细节。赞分享前端UI组件【免费下载链接】golden-layoutA multi window layout manager for webapps项目地址https://gitcode.com/gh_mirrors/go/golden-layout点击查看免费下载相关推荐Golden Layout组件绑定完全指南从基础绑定到动态更新的全流程Golden Layout组件绑定完全指南从基础绑定到动态更新的全流程 Golden Layout是一个强大的多窗口布局管理器能够帮助开发者轻松创建复杂的W前端UI组件naive-ui Date Picker 组件完全指南11 种类型、格式化绑定与面板定制naive ui Date Picker 组件完全指南11 种类型、格式化绑定与面板定制 本文以 naive ui 官方 Date Picker 演示文档前端UI组件TileLang GPU内核开发20行Python写出FP16 GEMMTileLang GPU内核开发20行Python写出FP16 GEMM 约80行Python就能让MLA解码在H100上追平手写FlashMLAFP16的编译器编程语言高性能计算人工智能深度学习上一篇UniHacker算法详解Boyer-Moore搜索算法的应用下一篇RoundedTB动态模式详解让你的Windows 11任务栏像macOS Dock一样智能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表