写在前面
如果你写过鸿蒙 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 style="color: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 四姿势的 demo
2.1 基础 Span:Text 内嵌五样式片段
typescript
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:单独点击事件
typescript
Text() {
Span('点这个 ')
Span('高亮词').fontColor('#E91E63').fontWeight(FontWeight.Bold)
.onClick(() => {
this.clickCount++
this.logText = `第 ${this.clickCount} 次:点了 Span「高亮词」`
})
Span(' 看日志变化')
}
Span 支持 .onClick()------点这个片段就触发回调,不影响其他 Span。这是富文本「可点击链接」的基础。
2.3 Span 嵌套 emoji 图标
typescript
Text() {
Span('状态:')
Span('✓ 在线').fontColor('#4CAF50').fontWeight(FontWeight.Bold)
Span(' ')
Span('✗ 离线').fontColor('#9E9E9E')
}
Span 内容支持 emoji------不用单独 Image 组件,直接文本嵌图标。
2.4 Span 动态样式(@State 驱动)
typescript
@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() } |
忘了 .decoration color |
下划线颜色错 | 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:
🔗 仓库地址 :atomgit.com/JaneConan/a...
仓库包含:
- 完整的「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 仓库:atomgit.com/JaneConan/a... 协议:Apache-2.0,随便用,别告我