写在前面如果你写过鸿蒙 ArkUI 应用大概率遇到过这个场景你写个用户协议页一行里有「普通文本 蓝色协议链接 加粗提示 下划线强调」四种样式。你用三个Text拼——结果换行错位、行高不齐、点击事件还分三份。 你查文档发现鸿蒙有个Span——Text容器内嵌的富文本片段每个 Span 单独设样式 onClick。你点进去发现 API 一脸懵。这是「多 Text 拼」和「Span 嵌套」的分水岭。鸿蒙给的富文本答案是Span——Text() { Span()...Span()... }内嵌多个样式片段一行对齐、单独样式、单独点击。本文就用一个真机可跑的「基础 Span 五样式 Span 点击 Span emoji Span 动态样式」demo把 Span 从「听名字一脸懵」讲到「下个项目直接抄」。代码托管在 AtomGit文末有链接真机实拍截图作证。这是组件深水区系列篇。适合人群写过鸿蒙应用、被「一行多样式」折磨过的同学。 不适合人群还在学State的同学——出门左转看我的入门篇。一、先讲清楚Span 到底是啥一句话Span 是鸿蒙 Text 容器内嵌的富文本片段每个 Span 单独设样式 onClick。你之前写前端span stylecolor:red红/span是浏览器宿主标签——鸿蒙不是浏览器环境没 HTML 标签。Span 是鸿蒙专门给富文本的原生组件能力对标前端的span但要在Text() { }内嵌使用。核心 API 一览API作用一句话理解Text() { Span()...Span()... }Text 内嵌多个 Span「Text 是容器Span 是片段」Span(内容)设文本内容「这个片段写啥」.fontColor()/.fontSize()/.fontWeight()/.fontStyle()Span 单独样式「这个片段啥样式」.decoration({type, color})下划线/删除线「TextDecorationType.Underline/LineThrough」.onClick()Span 单独点击「点这个片段触发啥」记住这六个往下看。二、动手一个 Span 四姿势的 demo2.1 基础 SpanText 内嵌五样式片段Text() { Span(这是普通文本) Span(红色加粗).fontColor(#F44336).fontWeight(FontWeight.Bold) Span() Span(蓝色斜体).fontColor(#2196F3).fontStyle(FontStyle.Italic) Span() Span(带下划线).decoration({ type: TextDecorationType.Underline, color: #000 }) Span() Span(20号大字).fontSize(20) }三个细节Text() { Span()...Span()... }——Text 用{ }内嵌多个 Span不是字符串拼接每个Span(内容)单独设样式——.fontColor/.fontWeight/.fontStyle/.fontSize.decoration({type, color})设下划线/删除线——TextDecorationType.Underline/LineThrough这是 Span 最核心的能力——一行内嵌多个样式片段行高对齐、不换行。2.2 Span onClick单独点击事件Text() { Span(点这个 ) Span(高亮词).fontColor(#E91E63).fontWeight(FontWeight.Bold) .onClick(() { this.clickCount this.logText 第 ${this.clickCount} 次点了 Span「高亮词」 }) Span( 看日志变化) }Span 支持.onClick()——点这个片段就触发回调不影响其他 Span。这是富文本「可点击链接」的基础。2.3 Span 嵌套 emoji 图标Text() { Span(状态) Span(✓ 在线).fontColor(#4CAF50).fontWeight(FontWeight.Bold) Span( ) Span(✗ 离线).fontColor(#9E9E9E) }Span 内容支持 emoji——不用单独 Image 组件直接文本嵌图标。2.4 Span 动态样式State 驱动State highlightWord: string 鸿蒙 State clickCount: number 0 Text() { Span(当前高亮).fontColor(#666) Span(this.highlightWord) .fontColor(this.clickCount % 2 0 ? #FF9800 : #9C27B0) .fontSize(18) .fontWeight(FontWeight.Bold) }Span 样式可绑State——this.highlightWord变了 Span 内容更新this.clickCount变了样式色切换。这是「动态高亮词」的基础。三、真机实拍Span 五样式 动态重绘我把这个 demo 装到真机上跑鸿蒙 6.1.1.125, API 24点底部「切换高亮词」按钮两次下面两张都是真机实拍没有任何 P 图。初始态① 基础 Span普通/红粗/蓝斜/下划线/20号大字 ② Span 点击事件 ③ Span emoji ④ Span 动态样式高亮「鸿蒙」橙色 日志区点切换两次后日志「第 2 次高亮词切到「ArkTS」」 ④ Span 动态样式高亮「ArkTS」紫色重点看第二张日志从「未点击」变成「第 2 次高亮词切到「ArkTS」」、④ Span 高亮词从「鸿蒙」橙色变成「ArkTS」紫色——Span 内容 样式都随 State 真重绘了。这是 Span 动态样式的真机证明。四、Span vs 多 Text 拼啥差异新手最容易纠结的问题既然多 Text 拼也能一行多样式鸿蒙为啥要造 Span维度多Text拼Span嵌套行对齐不齐行高各自算齐同一行行高换行各自换行错位一行内不换行点击事件分散各 Text单 Span 单 onClick性能多组件重单 Text 内轻代码量多3 个 Text少1 个 Text 3 Span一句话决策一行多样式必须用 Span 嵌套不能用多 Text 拼。五、常见坑都是血泪坑症状解法Span 装在 Text 外编译报错「Span 必须在 Text 内」Text() { Span()... }嵌套Span 用字符串拼接样式不生效Span 是组件不是字符串用Text() { Span() }忘了.decorationcolor下划线颜色错decoration({type, color})color 要显式Span onClick 影响其他点一个全行触发Span onClick 单独不影响其他 Span动态样式绑State不更新UI 不重绘State改值才重绘Span 装在Component里emoji 显示方块字体不支持鸿蒙默认字体支持 emoji方块是字体坑换字体六、Span 适用边界Span 不是万能——几个场景不适合场景用 Span 吗推荐组件一行多样式片段✅Span 嵌套多行段落❌多个 Text Column图片嵌文本❌Text Image Row富文本超链接✅Span onClick全文相同样式❌单 Text 设样式七、完整代码仓库本文所有代码都已托管到AtomGit欢迎 clone、提 issue、点 star仓库地址https://atomgit.com/JaneConan/arkui-span仓库包含完整的「Span 四姿势」demo 工程Index.ets主页面基础 Span 五样式 onClick emoji 动态样式可直接用 DevEco Studio 打开运行真机装普通应用必能跑八、下一步该学什么跑通这个 demo 之后你的鸿蒙富文本就入门了。后续按这个顺序往下Image 多源加载下一篇网络/本地/资源/沙箱四源List Section 分组吸顶大列表分组 sticky 头Swiper 自动轮播轮播 Indicator 自动播放ScrollView 嵌套滚动Scroll 容器 嵌套滚动Slider 滑块控制滑块 onChange step写在最后Span 的本质是**「鸿蒙给 Text 内嵌富文本片段的原生组件」**——不是多 Text 拼是单 Text 内多 Span 嵌套。代价是Text() { }内嵌多写一层。一旦你开始用 Span 思维写一行多样式你会发现大部分「协议页蓝链接」「状态行 emoji 高亮」「日志行加粗关键词」的需求都是 Span 嵌套的自然结果。代码量比多 Text 拼少一半对齐性高一倍。代码已经给你了仓库链接在上面。现在关掉这篇文章打开 DevEco Studio把 demo 跑起来亲手点切换高亮词感爱下 Span 动态重绘。跑通了回来评论区打个「1」我看看有多少人真的动手了。作者JaneConan 仓库https://atomgit.com/JaneConan/arkui-span 协议Apache-2.0随便用别告我