拓冰建站拓冰建站
首页 / 资讯中心 / 正文

IATA Rave 实战:用 Web Components 构建航空业统一设计系统

如果你曾参与过航空公司、机场或旅游分销平台的数字化项目大概率遇到过同一个尴尬业务系统多界面风格却各自为战同一个“航班查询”功能在不同系统中长着完全不同的脸。前端团队每接手一个新项目都要重新设计一遍基础组件既浪费时间又让用户学得头疼。IATA国际航空运输协会这几年在航空零售化和标准统一上做了不少事情其中一个面向行业前端的开源设计系统就是 Rave。简单说Rave 让航空行业的开发者可以基于一套统一的 UI 组件和设计规范去构建 Web 应用。本文围绕“成为 Rave 开发者”这个主题展开适合想进入航空业做前端或全栈的开发者也适合已经在航空 IT 项目中摸爬滚打、想提升组件化效率的团队。读完你会理解 Rave 解决了什么问题、它的技术栈长什么样并动手搭建第一个 Rave 风格的应用和自定义航班业务组件。正文中的代码属于工程示例Rave 的包名、组件前缀和 API 在不同版本中可能调整请以你当前使用的官方文档为准。1. 为什么航空行业需要 Rave 开发者1.1 航空 IT 的 UI 碎片化问题航空公司的数字化体系远比普通人想象中复杂。一套面向旅客的购票官网背后往往连接着 PSS 旅客服务系统、订单管理系统、支付网关、常旅客计划、机场离港系统等多个平台。这些系统来自不同供应商有些是几年前的旧系统有些是新上的云原生应用。消费者前端可以被设计得很漂亮但内部运营人员每天使用的后台工具仍然充满了表格式界面、密集表单和风格不一致的按钮。这种碎片化带来的不只是视觉问题还有真实的开发和维护成本。一个机场地服系统要增加一个“登机口变更”功能前端团队可能要从零写一套组件另一家供应商开发的同类系统又因为内部封装完全不同几乎所有代码都要重写。行业缺少的是一种可共享、可扩展的 UI 资产。Rave 的定位就是航空运输行业的开源设计系统和前端组件生态。它由 IATA 推动目标不是做一套“谁都通用的普通组件库”而是专注航空业务场景让航空公司、机场、技术供应商在同一个生态里协作。1.2 什么是 IATA Rave从技术角度看Rave 是一套基于现代 Web 标准构建的组件库与设计规范从行业角度看它是航空业数字化转型过程中的公共基础设施。Rave 组件覆盖了表单、表格、按钮、弹窗、日期选择等常用能力同时把颜色、字体、圆角、间距等视觉要素抽象成设计令牌方便团队在统一规范下做品牌化定制。Rave 与航空业务标准关系紧密。航空公司正在从传统“航班为中心”的销售模式转向“订单为中心”的零售模式这个过程中涉及 NDC 标准、One Order 标准等。Rave 的价值在于把这类航空业务模型在界面上做出一致的表达。比如乘客信息录入、行李选项、辅营产品选择、航班变更等场景都可以用同一套组件语言实现。所以“Rave 开发者”并不是只会用组件库的页面拼接工人而是既懂现代前端工程化又能把航空业务标准落地成高质量界面的一类角色。2. Rave 的技术架构与核心概念2.1 基于 Web ComponentsRave 最值得关注的技术选择是 Web Components。它由浏览器原生支持的自定义元素、Shadow DOM、HTML 模板等标准组成核心优势是框架无关。你不需要担心项目用的是 React 还是 Vue只要浏览器支持自定义元素就能直接使用 Rave 组件。这对航空行业尤其重要同一套组件库要被十几个不同技术栈的团队使用如果只提供 React 版本Vue 和 Angular 团队就难以复用但如果基于 Web Components 发布所有业务系统都能以最小成本接入。用户在页面中看到的是一个自定义元素标签例如一个按钮可能被渲染成rave-button。组件内部的 DOM 结构和样式被隔离在 Shadow DOM 中不轻易受到外部全局样式污染。这种封装特性在大型后台系统中非常实用。如果你刚开始接触这个概念可以把 Web Components 理解为“浏览器原生支持的组件化能力”。它不依赖某个框架的运行时定义一次随处使用。2.2 设计令牌与主题Rave 组件在样式层大量使用 CSS 变量也就是设计令牌。设计令牌并不是某个库的专属概念而是一种将颜色、字体、间距、圆角等设计决策集中管理的方式。通常 Rave 会在:root或特定主题作用域下定义一组变量例如主色、边框色、常用间距。组件内部通过var(--rv-color-primary)这类写法引用。这样业务系统可以基于一套变量定制品牌色而不需要重写组件源码。这种设计给航空企业带来的直接好处是下属子品牌或不同地区站点需要调整视觉时只需要覆盖主题变量不需要修改业务组件逻辑。后续升级组件库时也不会因为本地改动过多产生合并冲突。2.3 组件分层一个成熟的航空业务前端项目组件通常会分三个层次基础组件按钮、输入框、下拉菜单、表格、弹窗等。业务组件航班卡片、乘客信息表单、行李选项、优惠券选择器等。页面模板查询页、订单页、乘客管理页等完整界面。Rave 设计系统覆盖的范围越往上层越需要业务团队自己沉淀。基础组件可以直接复用 Rave 的能力业务组件则要结合航空领域的数据模型做封装。作为 Rave 开发者不能只满足于调用基础组件还要具备业务组件的抽象能力。3. 环境准备与开发工具3.1 开发环境在动手写代码之前先把基础环境准备好。Node.js 环境建议 16 或以上版本npm 或 yarn 任选。代码编辑器推荐 VS Code并安装 ESLint、Prettier 等前端工程化插件。现代浏览器推荐 Chrome 或 Edge用于调试自定义元素和 Shadow DOM。Git用于项目管理和提交代码。如果你是想用 Rave 官方组件开始需要先确认你的项目能访问 npm registry 并安装依赖。国内网络环境下如果安装慢可以配置 npm 镜像这里不做展开。3.2 项目脚手架本文的示例使用 Vite 构建一个原生 Web Components 项目。Vite 开发服务器启动快、配置简单适合用来做组件原型验证。# 创建项目 npm create vitelatest rave-demo -- --template vanilla # 进入目录 cd rave-demo # 安装依赖 npm install执行完后项目里会看到一个标准的index.html、main.js和style.css文件。后续我们会在这些文件上修改。3.3 关于版本与组件前缀Rave 组件库的发布形式和命名在不同阶段可能有变化。有些版本使用rv-*前缀有些版本使用rave-*前缀安装包名也可能从单包变为按模块拆分。所以尽量不要把“某个固定前缀”背死而是在项目中统一查文档或者在浏览器开发者工具的 Elements 面板里确认自定义元素的实际标签名。下面的示例中我会统一用rave-作为标签前缀目的是让结构更直观。你实际开发时请以官方文档暴露出来的标签名为准。4. 第一个 Rave 风格应用从零搭建4.1 引入组件库假设你已经通过 npm 安装了 Rave 的相关组件包。如果组件库是用 Stencil 这类工具构建的通常需要调用它的 loader 方法把自定义元素注册到浏览器中。在src/main.js中写入// 文件路径src/main.js import { defineCustomElements } from rave-components/dist/loader; defineCustomElements();这里的rave-components/dist/loader是示例写法。实际项目中请根据你安装的包名和导出路径调整。如果你是直接在一个普通 HTML 页面中使用也可以通过script标签引入组件库的构建产物。哪种方式适合你取决于项目架构和组件库官方给出的接入方式。4.2 在页面中使用组件修改index.html加入一个简单的航空订单创建界面!DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleRave Demo/title /head body main classpage h1航班订单管理/h1 rave-button>npm run dev浏览器打开终端提示的本地地址正常情况下页面会显示标题、按钮和输入框。打开开发者工具的 Elements 面板可以观察到这些标签内部存在 Shadow DOM 结构。这就是 Web Components 的典型表现。如果页面中组件没有渲染优先检查两个方面一是defineCustomElements是否在入口执行成功二是组件标签名称是否和官方文档一致浏览器不认识的标签会被当成普通行内元素无法看到组件效果。4.4 与主流框架集成Rave 的 Web Components 特性让集成变得简单。用 React 举例你仍然需要处理一个细节React 的 JSX 语法对自定义元素支持不算特别原生官方推荐通过createElement或 ref 结构使用。下面是一个在 React 组件中包装flight-card自定义元素的示例// 文件路径src/components/FlightCardWrapper.jsx import { useEffect, useRef, createElement } from react; export default function FlightCardWrapper(props) { const ref useRef(null); useEffect(() { const el ref.current; const handler (event) { console.log(用户选择航班:, event.detail); }; el?.addEventListener(flight-select, handler); return () el?.removeEventListener(flight-select, handler); }, []); return createElement(flight-card, { ...props, ref }); }这里的关键点是React 的合成事件只覆盖标准事件自定义事件flight-select需要拿到原生 DOM 元素后通过addEventListener手动监听并在组件卸载时移除监听器避免内存泄漏。如果你使用 TypeScript还需要给自定义元素声明类型否则 JSX 和createElement的类型校验会报“未知元素”的错。// 文件路径src/types/global.d.ts declare namespace JSX { interface IntrinsicElements { flight-card: React.DetailedHTMLProps React.HTMLAttributesHTMLElement, HTMLElement { from?: string; to?: string; deps-time?: string; arrs-time?: string; price?: string; }; } }5. 实战开发一个航空航班组件5.1 需求分析进入具体业务场景。假设我们要开发一个“航班卡片”组件用于在搜索结果列表中展示一条航班信息。需求包括展示出发地、目的地机场三字码。展示出发和到达时间。展示价格。点击卡片时触发一个自定义事件方便外部业务逻辑监听。这个组件既要符合 Rave 的设计语言又要保持业务上的可复用性。我们采用原生 Web Components 实现不依赖任何框架。5.2 设计令牌定义为了贴合 Rave 的设计系统我们先用一组 CSS 变量定义主题。/* 文件路径src/styles/tokens.css */ :root { --rv-color-primary: #005fc5; --rv-color-primary-hover: #004a9a; --rv-color-bg: #ffffff; --rv-color-border: #e5e7eb; --rv-color-text: #1f2937; --rv-color-text-secondary: #6b7280; --rv-font-family: Inter, PingFang SC, Microsoft YaHei, sans-serif; --rv-radius: 8px; --rv-space-sm: 8px; --rv-space-md: 16px; --rv-space-lg: 24px; }这些变量命名体现了 Rave 生态里常见的--rv-前缀。具体变量名以你使用的设计系统为准但思路是一致的把颜色、空间、字体这些可复用的设计决策沉淀成变量。5.3 航班卡片组件实现创建FlightCard组件类。// 文件路径src/components/FlightCard.js class FlightCard extends HTMLElement { static get observedAttributes() { return [from, to, deps-time, arrs-time, price]; } constructor() { super(); // 使用阴影 DOM 隔离内部样式 this.attachShadow({ mode: open }); } connectedCallback() { this.render(); this.bindEvents(); } attributeChangedCallback() { this.render(); } formatPrice(value) { const amount Number(value); if (Number.isNaN(amount)) { return --; } return new Intl.NumberFormat(zh-CN, { style: currency, currency: CNY }).format(amount); } bindEvents() { const card this.shadowRoot.querySelector(.card); card?.addEventListener(click, () { this.dispatchEvent( new CustomEvent(flight-select, { detail: { from: this.getAttribute(from), to: this.getAttribute(to), depsTime: this.getAttribute(deps-time), arrsTime: this.getAttribute(arrs-time), price: this.getAttribute(price) }, bubbles: true, composed: true }) ); }); } render() { const from this.getAttribute(from) || ---; const to this.getAttribute(to) || ---; const depsTime this.getAttribute(deps-time) || ; const arrsTime this.getAttribute(arrs-time) || ; const price this.formatPrice(this.getAttribute(price)); this.shadowRoot.innerHTML style :host { display: block; font-family: var(--rv-font-family, sans-serif); } .card { border: 1px solid var(--rv-color-border, #e5e7eb); border-radius: var(--rv-radius, 8px); padding: var(--rv-space-md, 16px); display: flex; justify-content: space-between; align-items: center; cursor: pointer; transition: box-shadow 0.2s ease; background: var(--rv-color-bg, #fff); } .card:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); } .airport { font-size: 20px; font-weight: 700; color: var(--rv-color-text, #1f2937); } .time { color: var(--rv-color-text-secondary, #6b7280); font-size: 14px; margin-top: 4px; } .price { color: var(--rv-color-primary, #005fc5); font-size: 18px; font-weight: 700; } /style div classcard rolebutton tabindex0 div div classairport${from} → ${to}/div div classtime${depsTime} — ${arrsTime}/div /div div classprice${price}/div /div ; } } customElements.define(flight-card, FlightCard);代码中有几个细节值得注意observedAttributes声明了组件监听哪些属性变化属性变化时会自动重新渲染。attachShadow({ mode: open })创建了隔离的样式作用域。render()方法是简单的字符串模板渲染适合组件内部状态不复杂的场景。formatPrice使用Intl.NumberFormat做货币格式化航空业务中涉及多语言、多币种时非常实用。composed: true的设置很关键它让自定义事件可以穿透 Shadow DOM被外层业务代码监听。如果你忘记设置composed事件可能无法正确向上冒泡。5.4 页面使用航班卡片在index.html中加入组件引用。flight-card fromPEK toSIN deps-time09:30 arrs-time15:45 price3680 /flight-card然后在主入口中注册组件。// 文件路径src/main.js import ./components/FlightCard.js; import ./styles/tokens.css;启动开发服务器后页面上应该能看到一张包含航班信息和价格的卡片。点击卡片控制台会打印出flight-select事件以及对应的航班明细。注意这里字段中的from、to在完整的航空业务中可能需要搭配城市名称而不仅仅是三字码。真实项目中你可以增加from-city、to-city等属性或者从后台接口直接返回完整的展示对象。5.5 组件测试思路这个组件是纯前端实现建议至少覆盖以下测试点属性不传时能否正常渲染且不报错。价格字段传入非法字符串时是否显示--。点击组件是否触发flight-select事件。重复更新属性时内容是否正确刷新。对于更复杂的业务组件建议引入 Playwright 做端到端测试在真实浏览器中验证自定义元素行为。6. 常见问题与排查思路Web Components 和 Rave 相关开发中最容易遇到下面几类问题。问题现象常见原因解决思路页面中自定义元素没有渲染loader 未调用、组件 JS 未加载、标签名拼写错误检查入口文件是否调用了defineCustomElements并用浏览器的 Elements 面板确认标签名Shadow DOM 内部样式异常写入了组件外部的全局样式或 CSS 变量没有被正确继承将样式定义在组件内部并有意识地使用 CSS 变量控制主题React 中自定义元素事件不生效JSX 合成事件无法覆盖自定义事件通过ref获取原生 DOM 元素用addEventListener手动绑定并在卸载时移除服务端渲染或构建时报window is not definedWeb Components 依赖浏览器 APINode 环境没有window在客户端动态导入组件包或使用dynamic import隔离组件之间有样式冲突全局使用非隔离性 CSS 类名推荐使用 Shadow DOM 或规范化类名遵循 Rave 的命名约定主题变量不生效变量定义在选择器优先级较低的位置或变量名不一致统一在:root定义并通过开发者工具检查元素的 Computed 样式这类问题的排查思路通常有一个共性先确认元素是否真正渲染再确认事件和样式层级。使用 Chrome DevTools 的 Elements 面板可以快速定位自定义元素的边界和 Shadow DOM 内部结构这是日常调试的推荐起点。7. 成为 Rave 开发者的最佳实践与学习路线7.1 从业务标准出发Rave 不只是一个 UI 组件库它背后是航空业对“零售化系统体验一致性”的追求。学习 Rave 时最好先理解几个航空业务概念NDC航空零售领域的 API 通信标准让航空公司能够动态地销售辅营产品。One Order用“订单”统一替代传统的“PNR E-Ticket EMD”多记录结构。机场三字码与航段时间航空界的基础数据概念。界面上的航班卡片、订单表单本质上都是这些业务模型的视觉表达。只有理解了字段含义才能在组件设计时做出合理的抽象。7.2 打好前端技术基础Rave 开发者能力的核心仍然是扎实的前端功底。建议按这个顺序学习HTML5 自定义元素、Shadow DOM、template与slot。TypeScript特别是泛型与声明文件编写。至少一门主流框架并理解框架与 Web Components 相互操作时的优缺点。设计系统基础包括设计令牌、主题化、可访问性。7.3 组件开发规范实际项目中我建议团队内部形成一套组件开发约定组件命名统一比如以flight-、order-、passenger-作为业务组件前缀。所有可配置的视觉内容尽量通过属性或 CSS 变量暴露而不是让使用方直接修改内部样式。每个组件必须考虑无属性和异常属性的渲染状态。事件名与组件名强关联例如flight-select、order-submit。在组件文档中记录可用的属性、事件、CSS 变量方便团队其他人接入。7.4 无障碍与国际化航空软件的用户来自全球各地无障碍和国际化不是加分项而是基础要求。颜色对比度需要满足 WCAG 标准。按钮、卡片等可交互元素要支持键盘操作。日期、时间要区分 UTC 与当地时间避免直接拼接字符串。货币金额尽量使用Intl.NumberFormat按地区格式化。7.5 参与开源与社区Rave 是开源设计系统意味着你可以通过阅读源码理解航空级组件的设计思路也可以通过提交 Issue、修复文档、贡献新组件来进入这个生态。参与开源的好处不仅仅是代码能力提升还能帮助你建立航空领域的人脉和行业认知。7.6 学习资源建议学习 Rave 和航空前端开发优先看这几类资源IATA 官方关于零售化标准和 Rave 的文档。Rave 设计系统官方组件示例与使用说明。Web Components 标准文档和 MDN 相关教程。GitHub 上航空领域开源项目特别是 Rave 相关仓库。如果所在公司已经有航空类项目争取在真实业务中沉淀一个业务组件远比只看文档有效。8. 写在最后Rave 的价值在于让航空行业的界面开发从“重复造轮子”走向“共享组件资产”。作为 Rave 开发者你不需要等整个行业标准完全成熟才开始行动。可以先从今天示例中的航班卡片组件入手把 Web Components、设计令牌、事件封装这几点练熟再逐步接触 IATA 的行业标准和更复杂的航空业务场景。航空业务系统的需求往往比普通企业应用更复杂数据和状态也更严肃。但正因如此一个懂得组件化、标准化和业务建模的前端开发者在这个行业里会非常有价值。如果你也想尝试建议第一步就是把环境搭好跑通一个最简单的 Rave 风格页面再往里面加业务组件。动手遇到问题的时候欢迎在评论区把报错信息发出来我们一起讨论排查思路。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门