HarmonyOS开发实战:小分享-TextEditPage文字编辑器——Header+TextArea+工具栏

前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

文字编辑器 是小分享 App 的核心功能之一,用户在此输入文字内容、调整格式,最终生成分享卡片。本篇以 TextEditPage 为例,讲解 Header 导航栏TextArea 多行输入@Builder 工具栏@State 双向绑定 等核心实现。详细 API 可参考 HarmonyOS TextArea 官方文档

一、TextEditPage 完整代码

1.1 页面完整实现

typescript 复制代码
import router from '@ohos.router';

@Entry
@Component
struct TextEditPage {
  @State textContent: string = '生活的美好在于分享';
  @State fontSize: number = 16;

  build() {
    Column() {
      // Header 导航栏
      Row() {
        Text('‹').fontSize(24).fontColor('#1A1A1A')
          .onClick(() => { router.back() })
        Text('文字编辑').fontSize(18).fontWeight(FontWeight.Bold)
          .fontColor('#1A1A1A').layoutWeight(1).textAlign(TextAlign.Center)
        Text('完成').fontSize(16).fontColor('#F5A623')
          .onClick(() => { router.pushUrl({ url: 'pages/PreviewPage' }) })
      }
      .width('100%').padding({ left: 16, right: 16, top: 12, bottom: 12 })
      .backgroundColor(Color.White)

      // 编辑区
      Scroll() {
        Column({ space: 16 }) {
          // 标题展示
          Text(this.textContent).fontSize(22).fontWeight(FontWeight.Bold)
            .fontColor('#1A1A1A').width('100%').padding({ left: 16, right: 16, top: 20 })

          // 多行输入
          TextArea({ text: '生活的美好在于分享...', placeholder: '输入你想分享的内容...' })
            .fontSize(15).fontColor('#333333').backgroundColor(Color.Transparent)
            .width('100%').height(300).padding({ left: 16, right: 16 })
            .onChange((value: string) => { this.textContent = value })

          // 配图占位
          Column() { Text('🌸').fontSize(60) }
            .width('100%').height(180).backgroundColor('#FFF8F0')
            .borderRadius(12).margin({ left: 16, right: 16 })
            .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
        }
      }
      .layoutWeight(1)

      // 底部工具栏
      Column() {
        // 工具行
        Row({ space: 0 }) {
          this.ToolItem('A', '样式')
          this.ToolItem('️', '排版')
          this.ToolItem('🎨', '背景')
          this.ToolItem('📷', '配图')
        }
        .width('100%').height(50).backgroundColor('#F8F8F8')
        .justifyContent(FlexAlign.SpaceAround)

        // 格式行
        Row({ space: 0 }) {
          this.FormatItem('A', '#F5A623')
          this.FormatItem('T', '#333333')
          this.FormatItem('', '#333333')
          this.FormatItem('', '#333333')
        }
        .width('100%').height(50).backgroundColor(Color.White)
        .justifyContent(FlexAlign.SpaceAround)
        .shadow({ radius: 4, color: '#10000000', offsetY: -2 })
      }
    }
    .width('100%').height('100%').backgroundColor(Color.White)
  }

  @Builder ToolItem(icon: string, label: string) {
    Column({ space: 2 }) {
      Text(icon).fontSize(18)
      Text(label).fontSize(10).fontColor('#666666')
    }
    .alignItems(HorizontalAlign.Center)
  }

  @Builder FormatItem(text: string, color: string) {
    Text(text).fontSize(18).fontColor(color).fontWeight(FontWeight.Bold)
  }
}

二、Header 导航栏

2.1 三栏布局

Header 采用左中右三栏布局:

typescript 复制代码
Row() {
  Text('‹')           // 左侧返回按钮
  Text('文字编辑')     // 居中标题
  Text('完成')         // 右侧操作按钮
}

2.2 布局结构

位置 内容 作用 样式
左侧 返回 fontSize 24, router.back()
居中 文字编辑 标题 fontSize 18, Bold, layoutWeight(1)
右侧 完成 确认 fontSize 16, #F5A623, 跳转预览页

三、TextArea 组件

3.1 基本用法

typescript 复制代码
TextArea({ text: '默认文字', placeholder: '输入你想分享的内容...' })
  .fontSize(15)
  .fontColor('#333333')
  .backgroundColor(Color.Transparent)
  .width('100%')
  .height(300)
  .padding({ left: 16, right: 16 })
  .onChange((value: string) => {
    this.textContent = value   // 状态绑定
  })

3.2 TextArea 常用属性

属性 作用 示例值
text 初始文本 '默认文字'
placeholder 占位符 '输入内容...'
onChange 内容变化回调 (value) => {}
maxLength 最大字符数 500
editable 是否可编辑 true
height 高度 300

3.3 代码块:TextInput 对比

typescript 复制代码
// TextInput - 单行输入
TextInput({ placeholder: '搜索...', text: this.searchKey })
  .onChange((value) => { this.searchKey = value })

// TextArea - 多行输入
TextArea({ text: this.textContent, placeholder: '输入内容...' })
  .height(300)
  .onChange((value) => { this.textContent = value })

四、@State 文本双向绑定

4.1 状态声明

typescript 复制代码
@State textContent: string = '生活的美好在于分享';
@State fontSize: number = 16;

4.2 双向绑定

typescript 复制代码
TextArea({ text: this.textContent, placeholder: '输入...' })
  .onChange((value: string) => {
    this.textContent = value  // 状态变化 → UI 自动刷新
  })

提示:onChange 回调中更新 @State 变量,ArkUI 会自动重新渲染依赖该变量的 UI 组件。

五、@Builder 工具栏

5.1 @Builder 定义

typescript 复制代码
@Builder ToolItem(icon: string, label: string) {
  Column({ space: 2 }) {
    Text(icon).fontSize(18)
    Text(label).fontSize(10).fontColor('#666666')
  }
  .alignItems(HorizontalAlign.Center)
}

@Builder FormatItem(text: string, color: string) {
  Text(text).fontSize(18).fontColor(color).fontWeight(FontWeight.Bold)
}

5.2 @Builder 调用

typescript 复制代码
Row({ space: 0 }) {
  this.ToolItem('A', '样式')
  this.ToolItem('️', '排版')
  this.ToolItem('🎨', '背景')
  this.ToolItem('📷', '配图')
}

5.3 @Builder 与 @Component 对比

对比维度 @Builder @Component
复用粒度 UI 片段 完整组件
状态管理 共享外部状态 独立状态管理
调用方式 this.xxx() 标签调用
适用场景 简单 UI 复用 复杂独立组件

六、编辑区布局

6.1 布局结构

text 复制代码
Scroll (可滚动)
  └─ Column (space: 16)
       ├─ Text (标题展示) 22px Bold
       ├─ TextArea (编辑区) 300px 高度
       └─ Column (配图占位) 180px #FFF8F0

6.2 配图占位区

typescript 复制代码
Column() { Text('🌸').fontSize(60) }
  .width('100%').height(180)
  .backgroundColor('#FFF8F0')
  .borderRadius(12)
  .margin({ left: 16, right: 16 })
  .justifyContent(FlexAlign.Center)
  .alignItems(HorizontalAlign.Center)

七、页面跳转流程

7.1 路由跳转

typescript 复制代码
// 返回按钮
router.back()

// 完成按钮 → 跳转预览页
router.pushUrl({ url: 'pages/PreviewPage' })

7.2 路由策略

按钮 路由 API 说明
‹ 返回 router.back() 返回编辑页
✕ 关闭 router.back() 返回首页
完成 router.pushUrl() 跳转预览页

八、常见问题

8.1 问题 1:TextArea 高度无法自适应

原因height 属性固定了高度,内容超出时会滚动。

解决 :不设置 height,让 TextArea 根据内容自动扩展。

8.2 问题 2:@State 更新后 UI 不刷新

原因:直接修改字符串变量是有效的,但如果修改对象属性需要创建新对象。

九、核心知识点

9.1 技术要点

  • TextArea 多行文本输入,支持 onChange 双向绑定
  • @State 管理编辑内容状态
  • 工具栏用 @Builder 封装复用
  • Header 三栏布局控制

9.2 实战建议

  • onChange 中更新 @State 实现双向绑定
  • 工具栏用 @Builder 复用 UI 片段
  • 完成按钮用 pushUrl 跳转预览页

总结

本文详细讲解了 TextEditPage 文字编辑器的完整实现,从 Header 三栏布局TextArea 多行输入@State 双向绑定@Builder 工具栏,涵盖了文字编辑器的全部核心功能。下一篇我们将深入 ImageEditPage 图片编辑器的实现。


相关资源


附录:编辑器的完整实现细节

1. 完整的 @Builder 工具栏

小分享 App 的 TextEditPage 使用两个工具栏行:工具行和格式行。工具行包含样式、排版、背景、配图四个功能入口;格式行包含字号加粗、斜体、下划线等格式控制。

typescript 复制代码
@Builder ToolItem(icon: string, label: string) {
  Column({ space: 2 }) {
    Text(icon).fontSize(18)
    Text(label).fontSize(10).fontColor('#666666')
  }
  .alignItems(HorizontalAlign.Center)
}

2. 路由跳转策略

按钮 目标 API 效果
‹ 返回 上一页 router.back() 出栈返回
完成 PreviewPage router.pushUrl() 入栈跳转

3. TextArea 与 TextInput 对比

对比维度 TextArea TextInput
行数 多行 单行
高度 可设置固定高度 自适应
滚动 内容溢出时自动滚动 不滚动
适用场景 文章编辑、评论输入 搜索框、用户名

4. 编辑区布局的完整代码

typescript 复制代码
Scroll() {
  Column({ space: 16 }) {
    // 标题展示
    Text(this.textContent)
      .fontSize(22).fontWeight(FontWeight.Bold).fontColor('#1A1A1A')
      .width('100%').padding({ left: 16, right: 16, top: 20 })

    // 多行输入
    TextArea({ text: '生活的美好在于分享...', placeholder: '输入你想分享的内容...' })
      .fontSize(15).fontColor('#333333').backgroundColor(Color.Transparent)
      .width('100%').height(300).padding({ left: 16, right: 16 })
      .onChange((value: string) => { this.textContent = value })

    // 配图占位区
    Column() { Text('🌸').fontSize(60) }
      .width('100%').height(180).backgroundColor('#FFF8F0')
      .borderRadius(12).margin({ left: 16, right: 16 })
      .justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
  }
}
.layoutWeight(1)

5. 完整的页码结构

text 复制代码
Column (主容器)
├─ Row (Header 导航栏) - 左‹ 中标题 右完成
├─ Scroll (编辑区) - layoutWeight(1) 撑开
│   └─ Column (space: 16)
│       ├─ Text (标题展示)
│       ├─ TextArea (编辑区)
│       └─ Column (配图占位)
└─ Column (底部工具栏)
    ├─ Row (工具行)
    └─ Row (格式行)

提示:以上布局结构是小分享 App 所有编辑器的标准模板,后续的 ImageEditPage 和 LinkEditPage 均采用类似的三段式布局。

6. 编辑器的扩展方向

扩展功能 实现方式 优先级
字号选择 @State fontSize + 滑动选择器
字体颜色 @State fontColor + 色板选择
加粗/斜体 @State isBold + Toggle 切换
对齐方式 @State textAlign + 三选一按钮
配图上传 PhotoViewPicker 选择图片

7. 完整的代码文件结构

text 复制代码
entry/src/main/ets/
├── pages/
│   └── TextEditPage.ets       # 文字编辑器页面
├── components/
│   └── StyleToolbar.ets       # 样式工具栏组件(可选抽取)
├── common/
│   └── interfaces.ets         # 公共接口定义
└── entryability/
    └── EntryAbility.ets       # 入口 Ability

上述文件结构展示了 TextEditPage 在小分享 App 工程中的位置。

  1. 第一步:了解组件的基本用法
  2. 第二步:掌握组件的核心属性

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

相关推荐
程序员cxuan2 小时前
Opus 5 深夜炸场,价格还挺香。。。
人工智能·后端·程序员
2501_918582372 小时前
HarmonyOS应用开发实战:小事记 - 应用包结构:HAP/HSP/HAR 的三层架构与 deliveryWithInstall 策略
华为·架构·harmonyos·鸿蒙
青山木2 小时前
Hot 100 ---腐烂的橘子
java·数据结构·后端·算法·leetcode·广度优先
卷无止境2 小时前
Python的collections模块:那些被低估的"瑞士军刀"
后端·python
不肥嘟嘟右卫门2 小时前
鸿蒙原生ArkTS布局方式之Scroll+Column+Sticky粘性布局深度解析
华为·harmonyos
卷无止境2 小时前
Python的方法解析顺序:一场关于继承顺序的精妙设计
后端·python
宁&沉沦2 小时前
Chrome 扩展 Manifest 字段版本支持一览(全量)
前端·后端·编辑器
<小智>2 小时前
鸿蒙多功能工具箱开发实战(二十四)-单元测试与自动化测试
ui·华为·harmonyos
youtootech3 小时前
HarmonyOS实战教程《台词拼图》(二)—— 响应式布局与断点系统
华为·harmonyos