在最近结束的“京东订单鸿蒙-回跨iOS/安卓”的项目中,NutUI 作为京东移动端的开源组件库,再次承担起一环重要的工作,为布局搭建、设计交互、无障碍、多语言、多模式实现等,提供了完备的基础能力,并出色的完成了三端的工作,基本实现了基于 Taro 框架的一码五端能力,开启了业内组件库跨端能力的新篇章。
基于业务与基建能力的重组
背景
在2024年到2025年,NutUI 基于鸿蒙和 iOS/安卓做了基本的适配工作,不过整体项目是实验中状态,最早在2024年发布了 DongDesign UI 的一码多端版本,并开放了鸿蒙支持的能力,整合了 Taro Components 及 NutUI 组件库,期望给开发者提供在 Taro 跨端中引用一套组件的便捷方式。
这是一个好的开端,让 Taro Components 和 NutUI 作为整合整体出现,这为在黄流跨端实现中提供了更直接的技术支持,并及时响应黄流业务侧提出的核心诉求——希望可以通过引用一个组件库,让整个项目在使用组件库的能力上更统一、规范、无痛。
很快,这件事达成了一致,并推动了第一版 黄流业务的基础组件库 落地——@hlfe/ui 的第一个版本的出现。@hlfe/ui 主要是为了赋能黄流业务侧,覆盖黄流订单、商详、购物车、结算,在优先考虑适配鸿蒙、iOS和安卓的前提下,初步整合了 Taro Components 公共组件及 NutUI 的 30+ 组件。组件的数量及能力,会继续随着业务侧的需求及基建适配能力陆续开放。

组件库间的关系
考虑到这一年多的时间内,突然出现了许多组件库的名字,这里首先对它们的关系做个厘清。

首先,我们可以简单粗暴的把它们的关系理解为上图的包含关系。Taro 作为框架,jdtaro/ui 是 Taro 提供的对外的基础组件,包含容器类、Form表单等基础能力,可看做是原来的 @tarojs/components 在 jd 域内的别名(目前这两个都可以引用,可关注 Taro 官网)。
第二,NutUI 在跨端能力是基于 Taro 框架来实现的, @jdtaro/ui (@tarojs/components) 是整个 NutUI 组件库的实现跨端的基座。
第三,@hlfe/ui 是面向黄流的开发者,包含前端、原生同学,为了让大家用起来省事、统一,将 NutUI 和 Taro 基础组件整合在一起,为大家提供了一个统一的引用入口。
未来,在其他业务场景里,如果实现一码五端,大家可以使用 hlfe/ui 来统一处理;也可以继续保留原引用逻辑。
hlfe/ui 的实现
hlfe/ui 的核心诉求是希望在项目中引用组件库的方式统一、集中,不用引多个 UI 组件库。所以,在实现中,也是以核心诉求为准,将项目中涉及的组件库收口处理。
双层组件架构
基于 Taro 的跨端项目中,项目依赖的组件主要来源于 Taro 基础组件库 jdtaro/ui 及基于主站实现的高阶组件库 NutUI,需要整合这两个组件库。在整合中,我们主要关注以下能力,以更好的服务业务。
1、基础组件与通用组件的整合
容器组件与通用组件的割裂,是导入两个组件库的根本原因。所以,在组件结构上,直接将两者可用组件导出。
| 组件库 | 组件列表 |
基础容器组件@jdtaro/ui | View、ScrollView、Text、List |
通用 UI 组件@nutui/nutui-react-taro | Button、Dialog、Toast、PopUp、Divider、Tabs、CheckBox、Radio、Switch、Empty、Input、TextArea、Price、CountDown、CalendarCard等 |
2、性能优先
在跨端的交付中,希望在满足交互复杂性的同时,会关注性能最优导出的策略。比如 Image ,我们优先会导出 jdtaro/ui 原组件,确保在各个端上都有实现此类组件的前提下,保障此类组件的性能最优;也会保留 NutUI 组件,并以 NutImage 导,以在基于端的性能优化下,保障组件功能的丰富性。
3、更多共用能力
1)类型定义:在跨端项目中,基本都使用了 TS,为了更兼容此类支持,在 hlfe/ui 中导出了组件定义相关的类型。
2)公共方法,在组件库中沉淀的一些高效公共方法,也一并为开发者提供,便于大家快速交付。
3)主题定义,Design Token 在组件库中的应用,方便大家可以快速的切换主题,包括正在支持的 京东到家、京犀 等主题;并直接为开发者提供相应的暗黑定义。
智能导出组件
通过构建脚本,完成了对组件最新能力的拉取、合并及导出。
// 导出 jdtaro/ui
indexContent.push(
`import { ${com.name} as T${com.name} } from '@jdtaro/ui'
const ${com.name} = T${com.name}
export {${com.name}}
`
)
// 导出 NutUI 公共组件
indexContent.push(`export { default as ${com.name} } from '@nutui/nutui-react-taro/dist/es/packages/${com.name.toLowerCase()}'`)
// 导出公共方法等
indexContent.push(`export * from '@nutui/nutui-react-taro/dist/es/utils'`)
indexContent.push(`export * from '@nutui/nutui-react-taro/dist/es/hooks'`)
hlfe/ui 的使用
创建项目
使用 jd-init搭建项目后,可选用 NutUI-React 模板,在完成项目后,进入项目配置。
taro jd-init my-taro-project
这时,需要关注几点:
确认包引入
1、在 package.json 中,确保已包含以下内容:
"@hlfe/ui": "0.0.3-cpp.ios.18-beta.10",
"@jdtaro/ui": "4.0.3-beta.34",
"@nutui/icons-react-taro": "3.0.2-cpp.3.beta.4",
"@nutui/nutui-react-taro": "3.0.19-cpp.23",
确认配置项
2、回跨到 iOS/安卓 项目时,需要关注 config/index.ts 中的配置,避免编译时异常:
esnextModules: [
'jdtaro',
'@hlfe/ui',
'@nutui/nutui-react-taro',
'@nutui/icons-react-taro',
],
组件使用
3、组件使用
import { Popup } from '@hlfe/ui'
return (
<Popup
visible={visible}
title={title}
position={position || `${isBigScreen ? 'right' : 'bottom'}`} // 大屏处理
closeable={parameter?.closeable ?? true}
{...rest} // 透传原组件属性
style={{ height, ...parameter.style, ...bigScreenRect, maxHeight: '100%' }}
closeAriaLabel={intl.formatMessage({ id: 'xxx_id' }) || '关闭'} // 无障碍读取配置
onClose={() => {
closePop()
parameter?.onClose?.(parameter?.outProps)
}}>
{content}
</Popup>
)
文档与反馈
| 文档 | https://nutui.jd.com/taro/react/3x/#/zh-CN/component/buttonhttps://npm.m.jd.com/package/@hlfe/ui |
| 咚咚群 | 1025679314 |
| 提交issue | https://github.com/jdf2e/nutui-react/issues |
核心能力的优化
hlfe/ui 的核心能力,是落在 Taro 的基础组件与 NutUI 的跨端适配上,本篇主要关注 NutUI 的跨端适配及能力建设。
在鸿蒙和回跨到 iOS/安卓项目中,最大的问题在于曾经在 web 和小程序端表现良好的布局与样式,会以各种奇怪的方式呈现,比如从中间弹出的弹框,会从右下方弹出;比如 Tabs 切换时,TabPane 成了白屏;比如主站不支持 SVG,Checkbox 就无法展示。这样的问题在项目中层出不穷,就需要一个一个的修改,并push上下游建设。
五端适配
区别于黄流业务的鸿蒙、iOS、安卓适配,作为基建,需要更多的关注在兼容已有能力的基础上实现新的适配。
Taro 基建为无法支持的属性与API 提供了工具,可以快速的识别到当前项目中,在 iOS 与 安卓上无法识别的能力。在运行以下命令后,需要特别关注 errors 信息,这些会阻塞业务项目的编译。
pnpm run build:dynamic --disable-upgrade --pages=pages/index/index --atom-collection --generate-source

在解决这些无法支持的属性与API时,主要考虑几点:
1)基础适配,如将原来的 div、span 等 web 端标签改为 Taro 标签。
2)兼容五端,通过判断端来做不同的处理。
/* #ifdef harmony dynamic*/
width: 80px;
/* #endif */
/* #ifndef harmony dynamic*/
width: auto;
/* #endif */
3)改进实现,规避不支持的属性或API。
// 不建议
left: -var(--nut-spacing);
align-items: start;
// 建议:
left: calc(-1 * var(--nut-spacing));
align-items: flex-start;
4)废弃 API 移除,如 getAppBaseInfo等。
能力扩充
在交付黄流的项目中,会对组件库提出更精确的需求,为此,对部分组件进行了功能扩充。
1)Popup 组件:支持拖拽变更半弹层的高度、支持 top 属性可供展示营销位等;
2)SearchBar 组件:增加 inputProps 属性,暴露更多的 input props 内置属性;
3)Input 组件:增加 style 属性透传至 native Input 组件;
4)Dialog 组件:底部按钮增加角标;
5)CountDown 组件:支持千分位展示;
6)Avatar 组件:支持图片填充模式;
7)NoticeBar 组件:优化宽度获取逻辑。
无障碍支持
为了更好的回跨,APP侧也对无障碍输出了统一的规范,基于整体规范,NutUI 也对无障碍进行了完善。
1)统一规范:
| 属性名 | 类型 | 说明 |
ariaRole | string | 角色 |
ariaLabel | string | 为元素提供一个可访问名称,通常用于没有可见文本说明的控件。 |
ariaHidden | boolean | 指定元素是否对辅助技术隐藏。true表示隐藏,false表示可访问。 |
ariaChecked | boolean | 用于复选框、开关等控件,标识当前是否被选中。 |
ariaSelected | boolean | 指示元素是否处于选中状态,常用于选项卡、列表项等。 |
ariaRoledescription | string | 为元素的role提供额外说明,帮助辅助技术进一步解释该元素的功能。 |
2)读取顺序:
ariaLabel→value→ariaRole→hint的顺序组合朗读。
3)当前实现:
在大部分的组件中,View 和 Text 读取是正常的,新增了如有交互行为的组件的无障碍属性,如 CheckBox、Radio等,支持 ariaLabel 的自定义。
4)已知问题及待解决:
在无障碍的实现中,iOS/安卓的表现相对来说较好。鸿蒙端,如弹出弹层时,无法自动获取焦点,需要手动触发可读取内容。类似问题会影响 Dialog、Toast、Popup 等弹层。
Icon 库升级
Icon 是组件中不可获取的部分,在实现鸿蒙/iOS/安卓的适配中,采用了 Image src 引入 svg 链接的方式。
import React from "react";
import "@tarojs/components";
const IconSVG = (props) => {
const realProps = { ...defaultProps, ...props };
return React.createElement(Icon2, { ...realProps, name: realProps.name || "Add", svgSrc: "https://storage.360buyimg.com/imgtools/81adb71e35-159c76f0-a824-11f0-8300-eb1b11b7ce6f.svg" }));
};
在实现中,难点在于推动主站 SVG 的基建,比如 无法展示 SVG,SVG 无法变更颜色,SVG 对于导出图片大小有要求。可喜的是,主站基建 SVG 的能力,目前正在向真实的 SVG 落地,对于图片库导出方来说,成本会显著降低。
![]() | ![]() |
![]() | ![]() |
同时,Icon 库也补齐了无障碍的能力,这样方便了开发者在使用 icon 时,可以做读取屏蔽或读取设置,大大方便了在项目中处理无障碍的设置。
比如在 CheckBox 组件中,对于 Icon 需要禁用可读。设置如下:
<Checked className={color()} ariaHidden />
而在组件维度,可以这样设置,保障组件的无障碍的支持:
<View
className={classNames(
classPrefix,
className
)}
{...rest}
onClick={handleClick}
ariaRole="checkbox"
ariaLabel={ariaLabel}
ariaChecked={innerIndeterminate ? 'mixed' : innerChecked}
>
<Checked className={color()} ariaHidden />
</View>
在项目内,可以这样设置:
<Checkbox
className={styles.checkbox}
checked={shipShopData?.venderShipmentVO?.selected}
ariaLabel='读取文案' // 或读取文案
// ariaHidden={true} // 或禁用掉
/>
回顾与总结
如今,@hlfe/ui 已开放了 30+ 组件,持续支持了 订单鸿蒙、订单iOS/安卓回跨、商详鸿蒙、结算鸿蒙、购物车鸿蒙;当前还在对商详、结算和购物车的回跨交付中,未来会对更多组件进行开放。
回顾这段时间,是与业务侧、Taro侧、基建能力紧密协作的一段历程。对于组件库与业务来说,都是一个快速迭代过程,其中也遇到了一些痛点,为此,我们希望可以在“提交issue-评审-提交PR-发布版本”的共建模式下,加快整个流程的执行落地,以快速响应业务侧的诉求,并给开发者提供更多共建的可能性。
邀请共建
欢迎更多的伙伴们,加入我们,一起共建,在一码五端的世界里遨游~
咚咚号:1025679314
Github: https://github.com/jdf2e/nutui-react
更多文章
升级你的前端开发体验: JoyCoder-VSCode现支持 NutUI工作区
特别鸣谢
感谢端技术、质量团队等团队的各位老板在过程中给予的充分指导,让整个项目始终按照正确的航向前行;
感谢整个项目组业务与基础建设相关项目产研测同学的密切合作,互相的充分信任是项目大胆向前的有力保障;
感谢各位上下游同学、平台同学、版本同学的鼎力支持,顺利解决了上下游依赖、高可用诉求、灰度验证等关键难题。
订单一码多端系列文章
•方案选型与总体设计:主站黄流的3倍效率革命试点:京东App订单一码多端整体回顾
•业务重构经验篇:订单模块Taro一码三端业务改造经验分享:从多端困境到动态化转型之路
•工程架构篇:京东黄流"一码三端"重构:规模化协作下的工程架构实践
•Taro SDK开发能力与效率篇:Taro 5.0:跨端架构演进与业务规模化落地实践
•性能优化篇:黄流订单列表性能优化实践:一码三端下的业务层性能攻坚之路
•公共组件篇:开启一码五端,NutUI 组件库助力黄流跨端实现
•CI/CD篇:黄流订单列表页CI/CD实践:一码三端项目业务层提效之路
•高可用篇:黄流订单一码多端高可用建设拆解:高速上换发动机的安全保障
•AI提效篇:Cursor + GPT‑5‑Codex:从“匆匆忙忙”到“从从容容”的跨端提效与质量保障实践









