- 前端
- UI组件
【免费下载链接】golden-layout
A multi window layout manager for webapps
Golden Layout(本仓库即 golden-layout,一个面向 Web 应用的多窗口布局管理器)在 2.0 版本中从 JavaScript 整体移植到了 TypeScript,并以此为契机对内部结构进行了大规模重构。本文以官方 Version 2 迁移说明 为骨架,结合仓库源码(config.ts、golden-layout.ts、layout-manager.ts 等)逐项梳理 v1(1.5.9)到 v2 的破坏性变更、弃用项与替代 API,帮助已有应用开发者完成平滑迁移,也帮助新使用者从一开始就采用正确的 v2 写法。
从 1.5.9 到 2.0:一次以可靠性为核心的 TypeScript 重写
v2 相对 v1(1.5.9)是一次实质性的大版本变更,官方总结为两点:
- 代码移植到 TypeScript:整个代码库以 TypeScript 重写,并同步完成了大范围的代码清理;
- 维护重心转向可靠性:v2 的维护工作将优先保证库本身的稳定与健壮。
由于这次重构力度很大,官方明确提示:在从 v1 迁移之前,务必先通读本节及以下各节的变更说明,尤其是"被移除的特性"与"弃用 API"两部分,避免在不知情的情况下依赖已失效的能力。
被移除的特性(Dropped Features)
作为移植的一部分,代码库被显著重构,一批在 v1 中"实现不够健壮、无法达到 v2 可靠性要求"的特性被正式移除:
| 被移除的特性 | 说明与替代方案 |
|---|---|
| React 支持 | 官方不再在 Golden Layout 内提供 React 组件支持,并建议 React 开发者改用专为 React 组件设计的 FlexLayout 库 |
| 嵌套 Stack(Nested Stacks) | v1 虽可拼出嵌套 Stack 布局,但实现并不完整;由于修复成本过高,官方决定直接移除该能力。v2 明确不允许嵌套 Stack |
| 内部/公开 API 混用 | 所有类、接口、函数与属性都被标记为internal或public两种之一,应用只能使用public元素(详见下文"Public and Internal APIs") |
| 旧浏览器支持 | 库现在只面向现代浏览器,目标浏览器列表(browserslist)配置在 package.json 中:最近 1 个版本的 Chrome / Firefox、最近 2 个版本的 Edge / Safari / iOS Safari,以及 Firefox ESR |
| jQuery 依赖 | Golden Layout 内部不再使用 jQuery(很多人把这视为新增特性而非损失) |
迁移到 v2 的总体原则
v2 用 TypeScript 重写并伴随整体代码清理。API 方面,官方尽量保留了向后兼容:凡是为兼容而保留的函数与属性都被标记为@deprecated,并强烈建议应用迁移到新 API。需要注意,弃用项相关的缺陷会被赋予低优先级(甚至不修复),且弃用的别名、方法与属性可能在后续版本中被移除。
Config 与 Resolved Config:双层配置体系
v2 最核心的架构变化是配置系统被拆成两层,并且全部强类型化:
- Config(配置):应用开发者日常打交道的类型。支持可选属性,未指定的属性会使用默认值;同时负责向后兼容,会把已弃用的旧属性自动迁移到新属性上。Golden Layout API 方法中的配置参数类型均为
Config(接口即LayoutConfig)。唯一的例外是LayoutManager.saveLayout(),它返回的是 Resolved Config; - Resolved Config(已解析配置):Golden Layout 内部统一使用 Resolved Config。每当 API 函数收到一个 Config,库内部会调用
LayoutConfig.resolve()将其解析为 Resolved Config——该过程为所有未指定的可选属性填充默认值,并处理向后兼容,从而保证库始终在"全量配置"下工作。从源码看,ResolvedLayoutConfig带有resolved: true标记字段,LayoutConfig.isResolved()正是据此区分两类对象(见 resolved-config.ts 与 config.ts)。
配置持久化的正确姿势
- 保存:总是保存
LayoutManager.saveLayout()返回的Resolved Config; - 加载:先通过
LayoutConfig.fromResolved()把保存的 Resolved Config 转回 Config,再交给loadLayout()。
ResolvedLayoutConfig还直接提供了两个配置压缩/解压函数:
minifyConfig()—— 递归地把配置的键与值替换为单字母代号,替代旧LayoutManager.minifyConfig();unminifyConfig()—— 把压缩后的配置还原,替代旧LayoutManager.unminifyConfig()。
这两者内部都经由ConfigMinifier.translateObject()实现(见 resolved-config.ts),并且弹窗窗口的配置传输(localStorage 中转)也依赖该机制(见 virtual-layout.ts)。
接口层级:ItemConfig 与 LayoutConfig
Resolved Config 与 Config 各自拥有两套接口层级:
ItemConfig:描述一个内容项(content item)的配置;LayoutConfig(v1 中名为Config的接口):描述整个布局的配置。
其中RowOrColumnItemConfig、StackItemConfig、ComponentItemConfig等均继承自ItemConfig;RootItemConfig表示可以作为布局根的内容项类型(row、column、stack、component四选一,见 config.ts)。
ItemConfig.id:类型收窄为string
ItemConfig.id的可选属性类型从 v1 的string | string[]收窄为string。为向后兼容,解析(resolve)时仍接受字符串数组类型的id,以兼容旧的已保存配置。解析规则(见HeaderedItemConfig.resolveIdAndMaximised(),config.ts):
- 若
id是数组,先检查其中是否包含旧版最大化标记__glMaximised,若存在则提取该标记作为maximised状态; - 数组的第一个元素成为
id的字符串值; - 其余元素被丢弃。
componentType取代componentName
ComponentItemConfig.componentName已被ComponentItemConfig.componentType取代。componentType的类型为JsonValue(即可被 JSON 序列化的任意值,可以是字符串、数字、布尔等),但如果该组件类型要通过以下任一函数注册,componentType必须为string类型:
GoldenLayout.registerComponent()(已弃用);GoldenLayout.registerComponentConstructor();GoldenLayout.registerComponentFactoryFunction()。
从源码看,解析时若componentType未定义会回退读取旧的componentName(见 config.ts);而getComponentInstantiator()通过ResolvedComponentItemConfig.resolveComponentTypeName()把componentType解析为注册表可用的字符串名称,非字符串的componentType将无法命中注册表(见 golden-layout.ts)。componentType是字符串时还会被用作组件标题的默认值(ComponentItemConfig.componentTypeToTitle())。
LayoutConfig.root:必填属性
LayoutConfig的root属性指定布局根内容项的ItemConfig,它不是可选的,必须始终指定(类型为RootItemConfig | undefined,其中undefined表示空布局,见 config.ts)。源码中的LayoutConfig.resolve()也保留了 v1 的兼容路径:若root未指定而旧content数组存在,则取content[0]作为根(见 config.ts)。
selectionEnabled移除,改用stackHeaderClick
LayoutConfig的selectionEnabled属性已被移除。点击 Stack 标题栏的选中行为改为通过新的stackHeaderClick事件处理,且该事件始终启用。
更多被弃用的 Config 属性
许多 Config 属性因为与其他属性重叠或迁移到了更合适的位置而被标记弃用,官方建议直接查阅源码注释了解详情:见 config.ts 中的@deprecated标注(如width/height→size,minWidth/minHeight→minSize,hasHeaders/showPopoutIcon/showCloseIcon/showMaximiseIcon→header下的show/popout/close/maximise等)。其中值得注意的新尺寸语法:
ItemConfig.size:格式为<数字><单位>,目前仅支持fr与%;对 row 表示高度、对 column 表示宽度。分配算法为:先按%比例分配空间,若不足 100% 则由fr按比例补足;若超过 100%,则给fr项额外分配 50% 后再统一回缩到 100%;ItemConfig.minSize:格式为<数字><单位>,目前仅支持px。
配置解析(parseSize())会对非数字部分、未知单位、不支持的单位分别抛出ConfigurationError(见 config.ts)。
创建LayoutConfig的完整可运行示例,可直接参考仓库中的 apitest 演示程序。
类层次:GoldenLayout → VirtualLayout → LayoutManager
v2 中GoldenLayout成为独立类,继承关系为:
LayoutManager(抽象基类) └── VirtualLayout └── GoldenLayout应用应总是创建GoldenLayout或VirtualLayout的实例,而不是直接实例化LayoutManager。
GoldenLayout/VirtualLayout构造函数接收 3 个可选参数:
- HTML 元素:承载 Golden Layout 实例的 DOM 元素;不指定时默认挂在
body下(setContainer()会把body的 height/margin/padding 重置为 0、overflow 设为 clip,见 layout-manager.ts); bindComponentEvent事件处理器:用于以事件方式绑定组件(v2 新增绑定方式);unbindComponentEvent事件处理器。
重要变更:初始布局不再传入构造函数,而是在构造后通过LayoutManager.loadLayout()加载。旧式的new GoldenLayout(config)构造签名仍在,但已被标记@deprecated(见 golden-layout.ts 的兼容重载)。
组件注册 API 的调整
v2 把组件注册职责收拢到GoldenLayout类中,LayoutManager不再包含任何组件注册函数。注册函数的具体变化:
registerComponentConstructor()(新函数):行为与旧registerComponent()相同,但仅用于注册组件构造函数;registerComponentFactoryFunction()(新函数):行为与旧LayoutManager.registerComponent()相同,但仅用于注册创建组件的回调函数(闭包);- 不要使用
registerComponent(),改用上述两个新函数之一。registerComponent()目前仍会按"是否有prototype属性"自动分派到构造函数或工厂函数注册,但已被标记弃用(见 golden-layout.ts)。
另外还有registerComponentFunction()(已弃用)与registerGetComponentConstructorCallback(),后者注册一个"按配置返回组件构造函数"的回调,仅在组件类型未注册时兜底调用(见 golden-layout.ts)。
LayoutManager 的方法迁移清单
LayoutManager是EventEmitter的抽象子类,v2 对其公开方法做了系统性调整,核心对照如下:
| v1 用法 | v2 用法 | 说明 |
|---|---|---|
new GoldenLayout(config, container) | new GoldenLayout(container)+loadLayout(config) | 构造后通过loadLayout()加载布局;loadLayout()可随时再次调用以整体替换当前布局(见 layout-manager.ts) |
手动调用init() | 不要手动调用 | 只要不在构造函数传入旧式 LayoutConfig,init()会被内部自动调用 |
toConfig() | saveLayout() | saveLayout()返回当前布局的Resolved Config(见 layout-manager.ts) |
minifyConfig()/unminifyConfig() | ResolvedLayoutConfig.minifyConfig()/unminifyConfig() | 迁移到 Resolved Config 上 |
updateSize() | setSize(width, height) | 以像素设置 Golden Layout 实例尺寸(见 layout-manager.ts) |
root(属性) | rootItem(新属性) | rootItem是布局的根内容项(Ground 内容项的唯一子级);root已被内部属性groundItem取代,且groundItem仅限内部使用 |
组件焦点(Focus)相关新 API
focusComponent(item, suppressEvent?):聚焦指定组件项。任意时刻只有一个组件项持有焦点;若此前有其他组件项聚焦,它会自动失焦(blur)。焦点变化时会触发对应的focus/blur事件,除非suppressEvent参数为true;clearComponentFocus(suppressEvent?):移除现有组件项焦点;若焦点被移除会触发blur事件,除非suppressEvent为true。
底层由LayoutManager.setFocusedComponentItem()实现:切换焦点时会先对旧焦点项调用setBlurred(),再对新项调用setFocused(),并同步更新父级(ComponentParentableItem)的聚焦态(见 layout-manager.ts)。
VirtualLayout 与组件绑定
VirtualLayout实现了除组件注册函数以外的全部 Golden Layout 功能;若应用只打算通过bindComponentEvent使用虚拟组件,可直接创建VirtualLayout实例而非GoldenLayout。
相关事件变更:
getComponentEvent:仍在VirtualLayout中实现,但已弃用,改用VirtualLayout.bindComponentEvent;releaseComponentEvent:已弃用,改用VirtualLayout.unbindComponentEvent。
关于 v2 引入的四种组件绑定方式(Embedding via Registration / Embedding via Events / Virtual via Registration / Virtual via Events)的完整说明、事件签名与代码示例,见 绑定组件(Binding Components)文档。
Content Items:命名与行为变化
v2 对内容项体系做了大量重命名与语义调整:
| v1 名称 | v2 名称 | 说明 |
|---|---|---|
AbstractContentItem | ContentItem | 内容项基类 |
ItemContainer | ComponentContainer | 组件容器 |
Component | ComponentItem | 布局内的组件项;"Component" 一词现在专指被 Golden Layout 承载的外部组件 |
Root | GroundItem | 已标记为 internal,应用永远不应访问 GroundItem;布局的根 ContentItem 是 GroundItem 的唯一子级,可通过LayoutManager.rootItem访问 |
Stack.getActiveContentItem()/setActiveContentItem() | Stack.getActiveComponentItem()/setActiveComponentItem() | 语义不变,仅更名 |
其余行为调整:
config属性已移除:改用toConfig()方法(这也是原版 Golden Layout 文档一直推荐的写法);此前config中的部分属性(如id、type)现在作为ContentItem或其子类的属性直接可用;id类型为string(不再支持string | string[]);ContentItem.select()/deselect()已移除:改用新的ComponentItem.focus()与ComponentItem.blur();ComponentItem.focus()(新函数):聚焦指定组件项,同时移除先前其他组件项的焦点,任意时刻只有一个组件项有焦点;若布局焦点发生变化会触发focus事件(除非suppressEvent为true);ComponentItem.blur()(新函数):移除指定组件项的焦点,调用后布局内将没有任何组件项持有焦点;若组件失去焦点会触发blur事件(除非suppressEvent为true)。
一个值得注意的实现细节:createContentItem()会自动为"不在 Stack 内的 Component 配置"包一层 Stack(除非它是弹窗窗口的顶层项),因此即使配置中直接写了component根项,最终也会以 Stack 容纳(见 layout-manager.ts)。
ComponentContainer 的新能力
ComponentContainer(旧ItemContainer)在 v2 中新增了多项能力:
element(新属性,替代getElement()):返回承载组件的 HTMLElement;getElement()已弃用;initialState(新 getter):获取创建该组件所用ComponentItemConfig的componentState;stateRequestEvent(新事件):一旦设置,每当 Golden Layout 需要组件的最新状态时就会触发该事件。调用LayoutManager.saveLayout()会触发它(若已定义);若未定义,则保存 ItemConfig 中的初始状态或最近一次setState()设置的状态;beforeComponentRelease(新 EventEmitter 事件):组件被释放前在容器上触发,组件可借此释放资源;setState()已标记弃用:如已迁移到新的stateRequestEvent,应优先使用该事件;只有仍在使用弃用的setState()时才继续用getState();replaceComponent():可在不影响布局其他部分的情况下替换容器内的组件(内部会先释放旧组件、用新 ItemConfig 重新绑定,见 component-container.ts)。
此外,虚拟组件绑定还依赖容器的virtualRectingRequiredEvent、virtualVisibilityChangeRequiredEvent、virtualZIndexChangeRequiredEvent等事件与virtual属性(用于区分虚拟/嵌入绑定方式),详见 component-container.ts 与 绑定组件文档。
Header 与 Tab:属性与函数重命名
header.ts 与 tab.ts 中有多个属性与函数被重命名,官方建议直接在这两个文件中搜索@deprecated标注来获取完整的改名对照清单。
事件系统升级
v2 的事件系统整体升级:
- 所有 DOM 事件现在都会向上传播,从而可被父级或全局处理;
- 任何事件监听器都不再调用
preventDefault(); - 冒泡事件现在携带
EventEmitter.BubblingEvent参数(或其子类)发出。
新增的 EventEmitter 事件:
| 事件 | 类型 | 触发时机 |
|---|---|---|
beforeComponentRelease | — | 组件被释放前 |
stackHeaderClick | Bubbling | 点击 Stack 标题栏(但非 Tab)时 |
stackHeaderTouchStart | Bubbling | 触摸 Stack 标题栏(但非 Tab)时 |
focus | Bubbling | 组件获得焦点时 |
blur | Bubbling | 组件失去焦点时 |
其它行为变化:undefined取代null
新属性、新事件等一律使用undefined而非null;部分内部实现也从null切换到undefined。旧属性大多保持null不变,但要注意:部分内部改动可能已波及外部属性/事件/方法的取值,迁移测试时建议覆盖此类边界。
Deprecations:弃用项的处理策略
大部分变更都保留了旧函数与旧属性,但统一标记为@deprecated。官方立场明确:
- 强烈建议应用重构以摆脱弃用项;
- 与弃用项相关的缺陷会被赋予低优先级(或完全不修复);
- 弃用的别名、方法、属性可能在未来的版本中被移除。
因此迁移不应停留在"能跑就行",而应把消灭弃用告警作为正式目标。
Public 与 Internal API 边界
v2 中所有 API 元素(类、接口、函数等)都被标注为public或internal:
- 应用只能使用
publicAPI 元素; internal元素随时可能变化,变更时不做任何向后兼容承诺。
库分发包含两份 TypeScript 声明(.d.ts)文件:
index.d.ts:只包含 public API 元素。应用应使用这份声明文件访问库;golden-layout-untrimmed.d.ts:包含全部(public + internal)API 元素。若确需访问库内任意元素可使用它,但请充分知悉上述风险。
官方同时说明:public/internal 的划分尚未最终定型,但任何在apitest演示程序或 Angular 示例应用中使用过的元素,都会保持为 public——这为迁移者提供了一个"安全区"判断依据。
迁移检查清单
综合全文,从 v1 迁移到 v2 时建议按以下顺序核对:
- 确认不依赖已移除特性(React 支持、嵌套 Stack、jQuery、旧浏览器);
- 构造函数改为
new GoldenLayout(container),布局通过loadLayout()加载; - 将
registerComponent()改为registerComponentConstructor()/registerComponentFactoryFunction(); - 把
toConfig()→saveLayout()、updateSize()→setSize()、root→rootItem、minifyConfig()/unminifyConfig()→ResolvedLayoutConfig上同名方法; - 配置中把
componentName改为componentType,width/height/minWidth/minHeight改为size/minSize,确认root已指定、id为string; - 持久化:保存
saveLayout()返回的 Resolved Config,加载前用LayoutConfig.fromResolved()转换; - 用
ComponentItem.focus()/blur()替代select()/deselect(),用Stack.getActiveComponentItem()替代旧命名; - 把
getElement()改为element属性,评估是否迁移到stateRequestEvent与beforeComponentRelease; - 组件绑定优先采用
bindComponentEvent/unbindComponentEvent(见 绑定组件文档),并处理stackHeaderClick等新事件; - 全程只使用 public API,以
index.d.ts为准,消灭所有@deprecated告警。
仓库中的 apitest 演示程序与 规格测试(如 drag-tests.ts、ground-item-tests.ts)是观察 v2 新 API 实际用法的最佳样例,迁移过程中可随时对照查阅。
- 前端
- UI组件
【免费下载链接】golden-layout
A multi window layout manager for webapps
相关推荐
Golden Layout 2.0 版本深度解析与迁移指南
Golden Layout 2.0 版本深度解析与迁移指南 前言 Golden Layout 是一个功能强大的Web布局管理器,允许开发者创建复杂的多面板界面。
前端UI组件ThingsBoard升级兼容性指南:API变更与数据迁移完整策略
ThingsBoard升级兼容性指南:API变更与数据迁移完整策略 ThingsBoard作为开源IoT平台,提供设备管理、数据收集、处理和可视化功能。随着版本
物联网后端数据可视化消息队列Tensorpack与TensorFlow 2.0兼容指南:平滑迁移策略
Tensorpack与TensorFlow 2.0兼容指南:平滑迁移策略 Tensorpack作为基于TensorFlow的高效神经网络训练接口,在Tensor
深度学习人工智能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考