HarmonyOS APP<玩转React>开源教程十九:CodeBlock 代码块组件
第19次:CodeBlock 代码块组件
代码展示是编程教程的核心功能。本次课程将开发 CodeBlock 组件,实现代码展示、复制功能和 Toast 提示反馈。
项目效果
学习目标
- 掌握代码展示组件设计
- 学会使用等宽字体
- 实现代码复制功能
- 使用剪贴板 API
- 实现 Toast 提示反馈
19.1 代码展示设计
组件结构
┌─────────────────────────────────────────┐ │ 标题 JSX 📋 │ ← 标题栏 ├─────────────────────────────────────────┤ │ function Example() { │ │ return <div>Hello</div>; │ ← 代码区域 │ } │ ├─────────────────────────────────────────┤ │ 💡 这是一个简单的函数组件示例 │ ← 解释说明 └─────────────────────────────────────────┘Props 定义
@Componentexportstruct CodeBlock{@Propcode:string='';// 代码内容@Proplanguage:string='javascript';// 编程语言@Proptitle:string='';// 标题@Propexplanation:string='';// 解释说明@StorageLink('isDarkMode')isDarkMode:boolean=false;}19.2 标题栏实现
标题栏布局
@BuilderTitleBar(){Row(){// 标题Text(this.title).fontSize(14).fontWeight(FontWeight.Medium).fontColor(this.isDarkMode?'#ffffff':'#1a1a2e')Blank()// 语言标签Text(this.language.toUpperCase()).fontSize(11).fontColor('#61DAFB').backgroundColor(this.isDarkMode?'rgba(97,218,251,0.2)':'rgba(97,218,251,0.1)').padding({left:6,right:6,top:2,bottom:2}).borderRadius(4)// 复制按钮Text('📋').fontSize(16).margin({left:12}).onClick(()=>this.copyCode())}.width('100%').padding({left:12,right:12,top:8,bottom:8}).backgroundColor(this.isDarkMode?'#1e1e1e':'#f1f3f5').borderRadius({topLeft:12,topRight:12})}条件显示标题栏
if(this.title){this.TitleBar()}19.3 代码区域实现
等宽字体
代码展示必须使用等宽字体(monospace),确保代码对齐:
Text(this.code).fontSize(13).fontFamily('monospace')// 等宽字体.fontColor(this.isDarkMode?'#e6e6e6':'#24292e')可滚动代码区域
Scroll(){Text(this.code).fontSize(13).fontFamily('monospace').fontColor(this.isDarkMode?'#e6e6e6':'#24292e').width('100%').padding(12)}.width('100%').constraintSize({maxHeight:300})// 限制最大高度.backgroundColor(this.isDarkMode?'#282c34':'#f6f8fa').borderRadius(this.title?{bottomLeft:12,bottomRight:12}:12).scrollBar(BarState.Auto)// 自动显示滚动条constraintSize 约束
使用constraintSize限制代码区域的最大高度,超出时显示滚动条:
.constraintSize({maxHeight:300,// 最大高度 300minHeight:50// 最小高度 50})19.4 代码复制功能
剪贴板 API
HarmonyOS 提供@kit.BasicServicesKit中的pasteboard模块操作剪贴板:
import{pasteboard}from'@kit.BasicServicesKit';复制实现
privatecopyCode():void{try{// 创建剪贴板数据constpasteboardData=pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN,// MIME 类型this.code// 数据内容);// 获取系统剪贴板constsystemPasteboard=pasteboard.getSystemPasteboard();// 设置数据到剪贴板systemPasteboard.setData(pasteboardData);// 显示成功提示promptAction.showToast({message:'代码已复制'});}catch(error){console.error('[CodeBlock] Failed to copy:',error);promptAction.showToast({message:'复制失败'});}}MIME 类型
| 类型 | 说明 |
|---|---|
| MIMETYPE_TEXT_PLAIN | 纯文本 |
| MIMETYPE_TEXT_HTML | HTML 文本 |
| MIMETYPE_TEXT_URI | URI |
19.5 Toast 提示反馈
promptAction API
import{promptAction}from'@kit.ArkUI';showToast 方法
promptAction.showToast({message:'代码已复制',// 提示文本duration:2000,// 显示时长(毫秒)bottom:100// 距底部距离});参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| message | string | 提示文本 |
| duration | number | 显示时长,默认 1500ms |
| bottom | number | 距底部距离 |
19.6 解释说明区域
实现代码
if(this.explanation){Text(this.explanation).fontSize(13).fontColor(this.isDarkMode?'#d1d5db':'#495057').padding(12).width('100%').backgroundColor(this.isDarkMode?'rgba(97,218,251,0.1)':'rgba(97,218,251,0.05)').borderRadius({bottomLeft:12,bottomRight:12})}19.7 完整组件代码
/** * 代码块组件 * 支持语法高亮和复制功能 */import{pasteboard}from'@kit.BasicServicesKit';import{promptAction}from'@kit.ArkUI';@Componentexportstruct CodeBlock{@Propcode:string='';@Proplanguage:string='javascript';@Proptitle:string='';@Propexplanation:string='';@StorageLink('isDarkMode')isDarkMode:boolean=false;build(){Column(){// 标题栏(如果有标题)if(this.title){Row(){Text(this.title).fontSize(14).fontWeight(FontWeight.Medium).fontColor(this.isDarkMode?'#ffffff':'#1a1a2e')Blank()// 语言标签Text(this.language.toUpperCase()).fontSize(11).fontColor('#61DAFB').backgroundColor(this.isDarkMode?'rgba(97,218,251,0.2)':'rgba(97,218,251,0.1)').padding({left:6,right:6,top:2,bottom:2}).borderRadius(4)// 复制按钮Text('📋').fontSize(16).margin({left:12}).onClick(()=>this.copyCode())}.width('100%').padding({left:12,right:12,top:8,bottom:8}).backgroundColor(this.isDarkMode?'#1e1e1e':'#f1f3f5').borderRadius({topLeft:12,topRight:12})}// 代码区域Scroll(){Text(this.code).fontSize(13).fontFamily('monospace').fontColor(this.isDarkMode?'#e6e6e6':'#24292e').width('100%').padding(12)}.width('100%').constraintSize({maxHeight:300}).backgroundColor(this.isDarkMode?'#282c34':'#f6f8fa').borderRadius(this.title?{bottomLeft:12,bottomRight:12}:12).scrollBar(BarState.Auto)// 解释说明if(this.explanation){Text(this.explanation).fontSize(13).fontColor(this.isDarkMode?'#d1d5db':'#495057').padding(12).width('100%').backgroundColor(this.isDarkMode?'rgba(97,218,251,0.1)':'rgba(97,218,251,0.05)').borderRadius({bottomLeft:12,bottomRight:12})}}.width('100%').borderRadius(12).clip(true)}privatecopyCode():void{try{constpasteboardData=pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN,this.code);constsystemPasteboard=pasteboard.getSystemPasteboard();systemPasteboard.setData(pasteboardData);promptAction.showToast({message:'代码已复制'});}catch(error){console.error('[CodeBlock] Failed to copy:',error);promptAction.showToast({message:'复制失败'});}}}19.8 使用示例
// 在课程详情页中使用CodeBlock({code:`function Welcome({ name }) { return <h1>Hello, {name}!</h1>; }`,language:'jsx',title:'函数组件示例',explanation:'这是一个接收 name 属性的函数组件'})本次课程小结
通过本次课程,你已经:
✅ 掌握了代码展示组件设计
✅ 学会了使用等宽字体
✅ 实现了代码复制功能
✅ 使用了剪贴板 API
✅ 实现了 Toast 提示反馈
课后练习
添加行号:为代码添加行号显示
添加语法高亮:实现简单的关键字高亮
添加展开/收起:长代码支持展开收起
下次预告
第20次:收藏功能实现
我们将开发收藏功能:
- BookmarkService 设计
- 收藏状态管理
- 收藏列表持久化
- 收藏页面实现
实现课程收藏功能!
