1# RichEditor 2 3支持图文混排和文本交互式编辑的组件。 4 5> **说明:** 6> 7> 该组件从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8> RichEditor[仅支持通过onDragStart事件](ts-universal-events-drag-drop.md)实现浮起等拖拽效果。 9 10## 子组件 11 12可以包含[Span](ts-basic-components-span.md)和[ImageSpan](ts-basic-components-imagespan.md)子组件。 13 14 15## 接口 16 17RichEditor(value: RichEditorOptions) 18 19**参数:** 20 21| 参数名 | 参数类型 | 必填 | 参数描述 | 22| -------- | -------- | -------- | -------- | 23| value | [RichEditorOptions](#richeditoroptions) | 是 | 富文本组件初始化选项。 | 24 25 26## 属性 27 28除支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性: 29 30> **说明:** 31> 32> 其中clip属性默认值为true。 33> align属性只支持上方丶中间和下方位置的对齐方式。 34 35| 名称 | 参数类型 | 描述 | 36| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 37| customKeyboard | [CustomBuilder](ts-types.md#custombuilder8) | 设置自定义键盘。<br/>**说明:**<br/>当设置自定义键盘时,输入框激活后不会打开系统输入法,而是加载指定的自定义组件。<br/>自定义键盘的高度可以通过自定义组件根节点的height属性设置,宽度不可设置,使用系统默认值。<br/>自定义键盘采用覆盖原始界面的方式呈现,不会对应用原始界面产生压缩或者上提。<br/>自定义键盘无法获取焦点,但是会拦截手势事件。<br/>默认在输入控件失去焦点时,关闭自定义键盘。 | 38| copyOptions | [CopyOptions](ts-appendix-enums.md#copyoptions9) | 组件支持设置文本内容是否可复制粘贴。<br />默认值:CopyOptions.LocalDevice <br/>**说明:** <br/>设置copyOptions为CopyOptions.InApp或者CopyOptions.LocalDevice,长按组件内容,会弹出文本默认选择菜单,可选中内容并进行复制、全选操作。<br/>设置copyOptions为CopyOptions.None,复制、剪切功能不生效。 | 39## 事件 40 41除支持[通用事件](ts-universal-events-click.md)外,还支持以下事件: 42 43| 名称 | 功能描述 | 44| ------------------------------------------------------------ | ------------------------------------------------------------ | 45| onReady(callback: () => void) | 富文本组件初始化完成后,触发回调。 | 46| onSelect(callback: (value: [RichEditorSelection](#richeditorselection)) => void) | 鼠标左键按下选择,松开左键后触发回调。<br />- value:选中的所有span信息。 | 47| aboutToIMEInput(callback: (value: [RichEditorInsertValue](#richeditorinsertvalue)) => boolean) | 输入法输入内容前,触发回调。<br />- value:输入法将要输入内容信息。 | 48| onIMEInputComplete(callback: (value: [RichEditorTextSpanResult](#richeditortextspanresult)) => void) | 输入法完成输入后,触发回调。<br />- value:输入法完成输入后的文本Span信息。 | 49| aboutToDelete(callback: (value: [RichEditorDeleteValue](#richeditordeletevalue)) => boolean) | 输入法删除内容前,触发回调。 <br />- value:准备删除的内容所在的文本Span信息。 | 50| onDeleteComplete(callback: () => void) | 输入法完成删除后,触发回调。 | 51 52## RichEditorInsertValue 53 54插入文本信息。 55 56| 名称 | 类型 | 必填 | 说明 | 57| -------- | -------- | -------- | -------- | 58| insertOffset | number | 是 | 插入的文本偏移位置。 | 59| insertValue | string | 是 | 插入的文本内容。 | 60 61 62## RichEditorDeleteValue 63 64| 名称 | 类型 | 必填 | 说明 | 65| -------- | -------- | -------- | -------- | 66| offset | number | 是 | 删除内容的偏移位置。 | 67| direction | [RichEditorDeleteDirection](#richeditordeletedirection) | 是 | 删除操作的方向。 | 68| length | number | 是 | 删除内容长度。 | 69| richEditorDeleteSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 是 | 删除的文本或者图片Span的具体信息。 | 70 71 72## RichEditorDeleteDirection 73 74删除操作的方向。 75 76| 名称 | 描述 | 77| -------- | ------------------------------ | 78| BACKWARD | 向后删除。 | 79| FORWARD | 向前删除。 | 80 81 82## RichEditorTextSpanResult 83 84文本Span信息。 85 86| 名称 | 类型 | 必填 | 说明 | 87| -------- | -------- | -------- | -------- | 88| spanPosition | [RichEditorSpanPosition](#richeditorspanposition) | 是 | Span位置。 | 89| value | string | 是 | 文本Span内容。 | 90| textStyle | [RichEditorTextStyleResult](#richeditortextstyleresult) | 是 | 文本Span样式信息。 | 91| offsetInSpan | [number, number] | 是 | 文本Span内容里有效内容的起始和结束位置。 | 92 93 94## RichEditorSpanPosition 95 96Span位置信息。 97 98| 名称 | 类型 | 必填 | 说明 | 99| -------- | -------- | -------- | -------- | 100| spanIndex | number | 是 | Span索引值。 | 101| spanRange | [number, number] | 是 | Span内容在RichEditor内的起始和结束位置。 | 102 103 104## RichEditorTextStyleResult 105 106后端返回的文本样式信息。 107 108| 名称 | 类型 | 必填 | 描述 | 109| ------ | -------- | ---- | -------------------------------------- | 110| fontColor | [ResourceColor](ts-types.md#resourcecolor) | 是 | 文本颜色。 | 111| fontSize | number | 是 | 字体大小。 | 112| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | 是 | 字体样式。 | 113| fontWeight | number | 是 | 字体粗细。 | 114| fontFamily | string | 是 | 字体列表。 | 115| decoration | {<br/>type: [TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br/>color: [ResourceColor](ts-types.md#resourcecolor)<br/>} | 是 | 文本装饰线样式及其颜色。 | 116 117 118## RichEditorImageSpanResult 119 120后端返回的图片信息。 121 122| 名称 | 类型 | 必填 | 描述 | 123|------------------|-------------------------------------------------------------------|-----|------------------| 124| spanPosition | [RichEditorSpanPosition](#richeditorspanposition) | 是 | Span位置。 | 125| valuePixelMap | [PixelMap](../apis/js-apis-image.md#pixelmap7) | 否 | 图片内容。 | 126| valueResourceStr | [ResourceStr](ts-types.md#resourcestr) | 否 | 图片资源id。 | 127| imageStyle | [RichEditorImageSpanStyleResult](#richeditorimagespanstyleresult) | 是 | 图片样式。 | 128| offsetInSpan | [number, number] | 是 | Span里图片的起始和结束位置。 | 129 130## RichEditorImageSpanStyleResult 131 132后端返回的图片样式信息。 133 134| 名称 | 类型 | 必填 | 描述 | 135| ------ | -------- | ---- | -------------------------------------- | 136| size | [number, number] | 是 | 图片的宽度和高度。 | 137| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | 是 | 图片垂直对齐方式。 | 138| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | 是 | 图片缩放类型。 | 139 140## RichEditorOptions 141 142RichEditor初始化参数。 143 144| 名称 | 类型 | 必填 | 说明 | 145| -------- | -------- | -------- | -------- | 146| controller | [RichEditorController](#richeditorcontroller) | 是 | 富文本控制器。 | 147 148 149## RichEditorController 150 151RichEditor组件的控制器。 152 153### 导入对象 154 155``` 156controller: RichEditorController = new RichEditorController() 157``` 158 159### getCaretOffset 160 161getCaretOffset(): number 162 163返回当前光标所在位置。 164 165**返回值:** 166 167| 类型 | 说明 | 168| ----------------------- | ---------------- | 169| number | 当前光标所在位置。 | 170 171### setCaretOffset 172 173setCaretOffset(offset: number): boolean 174 175设置光标位置。 176 177**参数:** 178 179| 参数名 | 参数类型 | 必填 | 参数描述 | 180| ------ | -------- | ---- | -------------------------------------- | 181| offset | number | 是 | 光标偏移位置。超出文本范围时,设置失败。 | 182 183**返回值:** 184 185| 类型 | 说明 | 186| ----------------------- | ---------------- | 187| boolean | 光标是否设置成功。 | 188 189### addTextSpan 190 191addTextSpan(value: string, options?: RichEditorTextSpanOptions): number 192 193添加文本内容。 194 195**参数:** 196 197| 参数名 | 参数类型 | 必填 | 参数描述 | 198| ------ | -------- | ---- | -------------------------------------- | 199| value | string | 是 | 文本内容。 | 200| options | [RichEditorTextSpanOptions](#richeditortextspanoptions) | 否 | 文本选项。 | 201 202**返回值:** 203 204| 类型 | 说明 | 205| ----------------------- | ---------------- | 206| number | 添加完成的Text Span所在的位置。 | 207 208### addImageSpan 209 210addImageSpan(value: PixelMap | ResourceStr, options?: RichEditorImageSpanOptions): number 211 212添加图片内容。 213 214**参数:** 215 216| 参数名 | 参数类型 | 必填 | 参数描述 | 217| ------ | -------- | ---- | -------------------------------------- | 218| value | [PixelMap](../apis/js-apis-image.md#pixelmap7)\|[ResourceStr](ts-types.md#resourcestr) | 是 | 图片内容。 | 219| options | [RichEditorImageSpanOptions](#richeditorimagespanoptions) | 否 | 图片选项。 | 220 221**返回值:** 222 223| 类型 | 说明 | 224| ----------------------- | ---------------- | 225| number | 添加完成的imageSpan所在的位置。 | 226 227 228### updateSpanStyle 229 230updateSpanStyle(value: RichEditorUpdateTextSpanStyleOptions | RichEditorUpdateImageSpanStyleOptions): void 231 232更新文本或者图片样式。<br/>若只更新了一个Span的部分内容,则会根据更新部分、未更新部分将该Span拆分为多个Span。 233 234**参数:** 235 236| 名称 | 类型 | 必填 | 描述 | 237| ------ | -------- | ---- | -------------------------------------- | 238| value | [RichEditorUpdateTextSpanStyleOptions](#richeditorupdatetextspanstyleoptions) \| [RichEditorUpdateImageSpanStyleOptions](#richeditorupdateimagespanstyleoptions) | 是 | 文本或者图片的样式选项信息。 | 239 240 241### getSpans 242 243getSpans(value?: RichEditorRange): Array<RichEditorTextSpanResult| RichEditorImageSpanResult> 244 245获取span信息。 246 247**参数:** 248 249| 参数名 | 参数类型 | 必填 | 参数描述 | 250| ------ | ----------------------------------- | ---- | ---------------- | 251| value | [RichEditorRange](#richeditorrange) | 否 | 需要获取span范围。 | 252 253**返回值:** 254 255| 类型 | 说明 | 256| ----------------------- | ---------------- | 257| Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 文本和图片Span信息。 | 258 259### deleteSpans 260 261deleteSpans(value?: RichEditorRange): void 262 263删除指定范围内的文本和图片。 264 265**参数:** 266 267| 参数名 | 参数类型 | 必填 | 参数描述 | 268| ------ | -------- | ---- | -------------------------------------- | 269| value | [RichEditorRange](#richeditorrange) | 否 | 删除范围。省略时,删除所有文本和图片。| 270 271 272## RichEditorSelection 273 274选中内容信息。 275 276| 名称 | 类型 | 必填 | 说明 | 277| --------- | ------------------------------------------------------------ | ---- | ---------- | 278| selection | [number, number] | 是 | 选中范围。 | 279| spans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)\| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 是 | span信息。 | 280 281 282## RichEditorUpdateTextSpanStyleOptions 283 284文本样式选项。 285 286| 名称 | 类型 | 必填 | 描述 | 287| ------ | -------- | ---- | -------------------------------------- | 288| start | number | 否 | 需要更新样式的文本起始位置,省略或者设置负值时表示从0开始。 | 289| end | number | 否 | 需要更新样式的文本结束位置,省略或者超出文本范围时表示无穷大。 | 290| textStyle | [RichEditorTextStyle](#richeditortextstyle) | 是 | 文本样式。 | 291 292 293## RichEditorUpdateImageSpanStyleOptions 294 295图片样式选项。 296 297| 名称 | 类型 | 必填 | 描述 | 298| ------ | -------- | ---- | -------------------------------------- | 299| start | number | 否 | 需要更新样式的图片起始位置,省略或者设置负值时表示从0开始。 | 300| end | number | 否 | 需要更新样式的图片结束位置,省略或者超出文本范围时表示无穷大。 | 301| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 是 | 图片样式。 | 302 303 304## RichEditorTextSpanOptions 305 306添加文本的偏移位置和文本样式信息。 307 308| 名称 | 类型 | 必填 | 描述 | 309| ------ | -------- | ---- | -------------------------------------- | 310| offset | number | 否 | 添加文本的位置。省略时,添加到所有文本字符串的最后。<br/>当值小于0时,放在字符串最前面;当值大于字符串长度时,放在字符串最后面。| 311| style | [RichEditorTextStyle](#richeditortextstyle) | 否 | 文本样式信息。省略时,使用系统默认文本信息。| 312 313## RichEditorTextStyle 314 315文本样式信息。 316 317| 名称 | 类型 | 必填 | 描述 | 318| ------ | -------- | ---- | -------------------------------------- | 319| fontColor | [ResourceColor](ts-types.md#resourcecolor) | 否 | 文本颜色。<br/> 默认值:Color.Black。 | 320| fontSize | [Length](ts-types.md#length) \| number | 否 | 设置字体大小,Length为number类型时,使用fp单位。字体默认大小16。不支持设置百分比字符串。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 321| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | 否 | 字体样式。<br/>默认值:FontStyle.Normal。 | 322| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | 否 | 字体粗细。<br/>number类型取值[100,900],取值间隔为100,默认为400,取值越大,字体越粗。<br/>string类型仅支持number类型取值的字符串形式,例如“400”,以及“bold”、“bolder”、“lighter”、“regular” 、“medium”分别对应FontWeight中相应的枚举值。<br/>默认值:FontWeight.Normal。 | 323| fontFamily | [ResourceStr](ts-types.md#resourcestr) | 否 | 设置字体列表。默认字体'HarmonyOS Sans',当前支持'HarmonyOS Sans'字体和[注册自定义字体](../apis/js-apis-font.md)。 <br/>默认字体:'HarmonyOS Sans'。 | 324| decoration | {<br/>type: [TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br/>color?: [ResourceColor](ts-types.md#resourcecolor)<br/>} | 否 | 设置文本装饰线样式及其颜色。<br />默认值:{<br/>type: TextDecorationType.None,<br/>color:Color.Black<br/>}。 | 325 326 327## RichEditorImageSpanOptions 328 329添加图片的偏移位置和图片样式信息。 330 331| 名称 | 类型 | 必填 | 描述 | 332| ------ | -------- | ---- | -------------------------------------- | 333| offset | number | 否 | 添加图片的位置。省略时,添加到所有文本字符串的最后。<br/>当值小于0时,放在字符串最前面;当值大于字符串长度时,放在字符串最后面。| 334| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 否 | 图片样式信息。省略时,使用系统默认图片信息。| 335 336## RichEditorImageSpanStyle 337 338图片样式。 339 340| 名称 | 类型 | 必填 | 描述 | 341| ------ | -------- | ---- | -------------------------------------- | 342| size | [[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)] | 否 | 图片宽度和高度。 | 343| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | 否 | 图片垂直对齐方式。<br/>默认值:ImageSpanAlignment.BASELINE | 344| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | 否 | 图片缩放类型。<br/> 默认值:ImageFit.Cover。 | 345 346## RichEditorRange 347 348范围信息。 349 350| 名称 | 类型 | 必填 | 描述 | 351| ------ | -------- | ---- | -------------------------------------- | 352| start | number | 否 | 起始位置,省略或者设置负值时表示从0开始。 | 353| end | number | 否 | 结束位置,省略或者超出文本范围时表示无穷大。 | 354 355 356## 示例 357 358### 示例1 359 360```ts 361// xxx.ets 362@Entry 363@Component 364struct Index { 365 controller: RichEditorController = new RichEditorController() 366 options: RichEditorOptions = { controller: this.controller } 367 private start: number = -1 368 private end: number = -1 369 @State message: string = "[-1, -1]" 370 @State content: string = "" 371 372 build() { 373 Column() { 374 Column() { 375 Text("selection range:").width("100%") 376 Text() { 377 Span(this.message) 378 }.width("100%") 379 Text("selection content:").width("100%") 380 Text() { 381 Span(this.content) 382 }.width("100%") 383 } 384 .borderWidth(1) 385 .borderColor(Color.Red) 386 .width("100%") 387 .height("20%") 388 389 Row() { 390 Button("更新样式:加粗").onClick(() => { 391 this.controller.updateSpanStyle({ 392 start: this.start, 393 end: this.end, 394 textStyle: 395 { 396 fontWeight: FontWeight.Bolder 397 } 398 }) 399 }) 400 Button("获取选择内容").onClick(() => { 401 this.content = "" 402 this.controller.getSpans({ 403 start: this.start, 404 end: this.end 405 }).forEach(item => { 406 if(typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'){ 407 this.content += (item as RichEditorImageSpanResult).valueResourceStr 408 this.content += "\n" 409 } else { 410 this.content += (item as RichEditorTextSpanResult).value 411 this.content += "\n" 412 } 413 }) 414 }) 415 Button("删除选择内容").onClick(() => { 416 this.controller.deleteSpans({ 417 start: this.start, 418 end: this.end 419 }) 420 this.start = -1 421 this.end = -1 422 this.message = "[" + this.start + ", " + this.end + "]" 423 }) 424 } 425 .borderWidth(1) 426 .borderColor(Color.Red) 427 .width("100%") 428 .height("10%") 429 430 Column() { 431 RichEditor(this.options) 432 .onReady(() => { 433 this.controller.addTextSpan("0123456789", 434 { 435 style: 436 { 437 fontColor: Color.Orange, 438 fontSize: 30 439 } 440 }) 441 this.controller.addImageSpan($r("app.media.icon"), 442 { 443 imageStyle: 444 { 445 size: ["57px", "57px"] 446 } 447 }) 448 this.controller.addTextSpan("0123456789", 449 { 450 style: 451 { 452 fontColor: Color.Black, 453 fontSize: 30 454 } 455 }) 456 }) 457 .onSelect((value: RichEditorSelection) => { 458 this.start = value.selection[0] 459 this.end = value.selection[1] 460 this.message = "[" + this.start + ", " + this.end + "]" 461 }) 462 .aboutToIMEInput((value: RichEditorInsertValue) => { 463 console.log("---------------------- aboutToIMEInput ----------------------") 464 console.log("insertOffset:" + value.insertOffset) 465 console.log("insertValue:" + value.insertValue) 466 return true 467 }) 468 .onIMEInputComplete((value: RichEditorTextSpanResult) => { 469 console.log("---------------------- onIMEInputComplete ---------------------") 470 console.log("spanIndex:" + value.spanPosition.spanIndex) 471 console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]") 472 console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]") 473 console.log("value:" + value.value) 474 }) 475 .aboutToDelete((value: RichEditorDeleteValue) => { 476 console.log("---------------------- aboutToDelete --------------------------") 477 console.log("offset:" + value.offset) 478 console.log("direction:" + value.direction) 479 console.log("length:" + value.length) 480 value.richEditorDeleteSpans.forEach(item => { 481 console.log("---------------------- item --------------------------") 482 console.log("spanIndex:" + item.spanPosition.spanIndex) 483 console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]") 484 console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]") 485 if (typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 486 console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr) 487 } else { 488 console.log("text:" + (item as RichEditorTextSpanResult).value) 489 } 490 }) 491 return true 492 }) 493 .onDeleteComplete(() => { 494 console.log("---------------------- onDeleteComplete ------------------------") 495 }) 496 .borderWidth(1) 497 .borderColor(Color.Green) 498 .width("100%") 499 .height("30%") 500 } 501 .borderWidth(1) 502 .borderColor(Color.Red) 503 .width("100%") 504 .height("70%") 505 } 506 } 507} 508``` 509 510 511### 示例2 512 513```ts 514// xxx.ets 515@Entry 516@Component 517struct RichEditorExample { 518 controller: RichEditorController = new RichEditorController() 519 520 // 自定义键盘组件 521 @Builder CustomKeyboardBuilder() { 522 Column() { 523 Grid() { 524 ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => { 525 GridItem() { 526 Button(item + "") 527 .width(110).onClick(() => { 528 this.controller.addTextSpan(item + '', { 529 offset: this.controller.getCaretOffset(), 530 style: 531 { 532 fontColor: Color.Orange, 533 fontSize: 30 534 } 535 }) 536 this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length) 537 }) 538 } 539 }) 540 }.maxCount(3).columnsGap(10).rowsGap(10).padding(5) 541 }.backgroundColor(Color.Gray) 542 } 543 544 build() { 545 Column() { 546 RichEditor({ controller: this.controller }) 547 // 绑定自定义键盘 548 .customKeyboard(this.CustomKeyboardBuilder()).margin(10).border({ width: 1 }) 549 .height(200) 550 .borderWidth(1) 551 .borderColor(Color.Red) 552 .width("100%") 553 } 554 } 555} 556``` 557 558 559