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| copyOption | [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| size | [number, number] | 是 | 图片的宽度和高度。 | 125| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | 是 | 图片垂直对齐方式。 | 126| objectFit | [ImageFit](ts-basic-components-imagespan.md#imagefit) | 是 | 图片缩放类型。 | 127 128 129## RichEditorOptions 130 131RichEditor初始化参数。 132 133| 名称 | 类型 | 必填 | 说明 | 134| -------- | -------- | -------- | -------- | 135| controller | [RichEditorController](#richeditorcontroller) | 是 | 富文本控制器。 | 136 137 138## RichEditorController 139 140RichEditor组件的控制器。 141 142### 导入对象 143 144``` 145controller: RichEditorController = new RichEditorController() 146``` 147 148### getCaretOffset 149 150getCaretOffset(): number 151 152返回当前光标所在位置。 153 154**返回值:** 155 156| 类型 | 说明 | 157| ----------------------- | ---------------- | 158| number | 当前光标所在位置。 | 159 160### setCaretOffset 161 162setCaretOffset(offset: number): boolean 163 164设置光标位置。 165 166**参数:** 167 168| 参数名 | 参数类型 | 必填 | 参数描述 | 169| ------ | -------- | ---- | -------------------------------------- | 170| offset | number | 是 | 光标偏移位置。超出文本范围时,设置失败。 | 171 172**返回值:** 173 174| 类型 | 说明 | 175| ----------------------- | ---------------- | 176| boolean | 光标是否设置成功。 | 177 178### addTextSpan 179 180addTextSpan(value: string, options?: RichEditorTextSpanOptions): number 181 182添加文本内容。 183 184**参数:** 185 186| 参数名 | 参数类型 | 必填 | 参数描述 | 187| ------ | -------- | ---- | -------------------------------------- | 188| value | string | 是 | 文本内容。 | 189| options | [RichEditorTextSpanOptions](#richeditortextspanoptions) | 否 | 文本选项。 | 190 191**返回值:** 192 193| 类型 | 说明 | 194| ----------------------- | ---------------- | 195| number | 添加完成的Text Span所在的位置。 | 196 197### addImageSpan 198 199addImageSpan(value: PixelMap | ResourceStr, options?: RichEditorImageSpanOptions): number 200 201添加图片内容。 202 203**参数:** 204 205| 参数名 | 参数类型 | 必填 | 参数描述 | 206| ------ | -------- | ---- | -------------------------------------- | 207| value | [PixelMap](../apis/js-apis-image.md#pixelmap7)\|[ResourceStr](ts-types.md#ResourceStr) | 是 | 图片内容。 | 208| options | [RichEditorImageSpanOptions](#richeditorimagespanoptions) | 否 | 图片选项。 | 209 210**返回值:** 211 212| 类型 | 说明 | 213| ----------------------- | ---------------- | 214| number | 添加完成的imageSpan所在的位置。 | 215 216 217### updateSpanStyle 218 219updateSpanStyle(value: RichEditorUpdateTextSpanStyleOptions | RichEditorUpdateImageSpanStyleOptions): void 220 221更新文本或者图片样式。<br/>若只更新了一个Span的部分内容,则会根据更新部分、未更新部分将该Span拆分为多个Span。 222 223**参数:** 224 225| 名称 | 类型 | 必填 | 描述 | 226| ------ | -------- | ---- | -------------------------------------- | 227| value | [RichEditorUpdateTextSpanStyleOptions](#richeditorupdatetextspanstyleoptions) \| [RichEditorUpdateImageSpanStyleOptions](#richeditorupdatetextspanstyleoptions) | 是 | 文本或者图片的样式选项信息。 | 228 229 230### getSpans 231 232getSpans(value?: RichEditorRange): Array<RichEditorTextSpanResult| RichEditorImageSpanResult> 233 234获取span信息。 235 236**参数:** 237 238| 参数名 | 参数类型 | 必填 | 参数描述 | 239| ------ | ----------------------------------- | ---- | ---------------- | 240| value | [RichEditorRange](#richeditorrange) | 否 | 需要获取span范围。 | 241 242**返回值:** 243 244| 类型 | 说明 | 245| ----------------------- | ---------------- | 246| Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 文本和图片Span信息。 | 247 248### deleteSpans 249 250deleteSpans(value?: RichEditorRange): void 251 252删除指定范围内的文本和图片。 253 254**参数:** 255 256| 参数名 | 参数类型 | 必填 | 参数描述 | 257| ------ | -------- | ---- | -------------------------------------- | 258| value | [RichEditorRange](#richeditorrange) | 否 | 删除范围。省略时,删除所有文本和图片。| 259 260 261## RichEditorSelection 262 263选中内容信息。 264 265| 名称 | 类型 | 必填 | 说明 | 266| --------- | ------------------------------------------------------------ | ---- | ---------- | 267| selection | [number, number] | 是 | 选中范围。 | 268| spans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)\| [RichEditorImageSpanResult](#richeditorimagespanresult)> | 是 | span信息。 | 269 270 271## RichEditorUpdateTextSpanStyleOptions 272 273文本样式选项。 274 275| 名称 | 类型 | 必填 | 描述 | 276| ------ | -------- | ---- | -------------------------------------- | 277| start | number | 否 | 需要更新样式的文本起始位置,省略或者设置负值时表示从0开始。 | 278| end | number | 否 | 需要更新样式的文本结束位置,省略或者超出文本范围时表示到结尾。 | 279| textStyle | [RichEditorTextStyle](#richeditortextstyle) | 是 | 文本样式。 | 280 281 282## RichEditorUpdateImageSpanStyleOptions 283 284图片样式选项。 285 286| 名称 | 类型 | 必填 | 描述 | 287| ------ | -------- | ---- | -------------------------------------- | 288| start | number | 否 | 需要更新样式的图片起始位置,省略或者设置负值时表示从0开始。 | 289| end | number | 否 | 需要更新样式的图片结束位置,省略或者超出文本范围时表示到结尾。 | 290| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 是 | 图片样式。 | 291 292 293## RichEditorTextSpanOptions 294 295添加文本的偏移位置和文本样式信息。 296 297| 名称 | 类型 | 必填 | 描述 | 298| ------ | -------- | ---- | -------------------------------------- | 299| offset | number | 否 | 添加文本的位置。省略时,添加到所有文本字符串的最后。 | 300| style | [RichEditorTextStyle](#richeditortextstyle) | 否 | 文本样式信息。省略时,使用系统默认文本信息。| 301 302## RichEditorTextStyle 303 304文本样式信息。 305 306| 名称 | 类型 | 必填 | 描述 | 307| ------ | -------- | ---- | -------------------------------------- | 308| fontColor | [ResourceColor](ts-types.md#resourcecolor) | 否 | 文本颜色。<br/> 默认值:Color.Black。 | 309| fontSize | [Length](ts-types.md#length) | 否 | 设置字体大小,Length为number类型时,使用fp单位。字体默认大小16。不支持设置百分比字符串。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 310| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | 否 | 字体样式。<br/>默认值:FontStyle.Normal。 | 311| 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。 | 312| fontFamily | [ResourceStr](ts-types.md#resourcestr) \| number \| string | 否 | 设置字体列表。默认字体'HarmonyOS Sans',当前支持'HarmonyOS Sans'字体和[注册自定义字体](../apis/js-apis-font.md)。 <br/>默认字体:'HarmonyOS Sans'。| 313| 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/>}。 | 314 315 316## RichEditorImageSpanOptions 317 318添加图片的偏移位置和图片样式信息。 319 320| 名称 | 类型 | 必填 | 描述 | 321| ------ | -------- | ---- | -------------------------------------- | 322| offset | number | 否 | 添加图片的位置。省略时,添加到所有文本字符串的最后。 | 323| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | 否 | 图片样式信息。省略时,使用系统默认图片信息。| 324 325## RichEditorImageSpanStyle 326 327图片样式。 328 329| 名称 | 类型 | 必填 | 描述 | 330| ------ | -------- | ---- | -------------------------------------- | 331| size | [[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)] | 否 | 图片宽度和高度。 | 332| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | 否 | 图片垂直对齐方式。<br/>默认值:ImageSpanAlignment.BASELINE | 333| objectFit | [ImageFit](ts-appendix-enums.md#imagefit) | 否 | 图片缩放类型。<br/> 默认值:ImageFit.Cover。 | 334 335## RichEditorRange 336 337范围信息。 338 339| 名称 | 类型 | 必填 | 描述 | 340| ------ | -------- | ---- | -------------------------------------- | 341| start | number | 否 | 起始位置,省略或者设置负值时表示从0开始。 | 342| end | number | 否 | 结束位置,省略或者超出文本范围时表示到结尾。 | 343 344 345## 示例 346 347### 示例1 348 349```ts 350// xxx.ets 351@Entry 352@Component 353struct Index { 354 controller: RichEditorController = new RichEditorController(); 355 options: RichEditorOptions = { controller: this.controller }; 356 private start: number = -1; 357 private end: number = -1; 358 @State message: string = "[-1, -1]" 359 @State content: string = "" 360 361 build() { 362 Column() { 363 Column() { 364 Text("selection range:").width("100%") 365 Text() { 366 Span(this.message) 367 }.width("100%") 368 Text("selection content:").width("100%") 369 Text() { 370 Span(this.content) 371 }.width("100%") 372 } 373 .borderWidth(1) 374 .borderColor(Color.Red) 375 .width("100%") 376 .height("20%") 377 378 Row() { 379 Button("更新样式:加粗").onClick(() => { 380 this.controller.updateSpanStyle({ 381 start: this.start, 382 end: this.end, 383 textStyle: 384 { 385 fontWeight: FontWeight.Bolder 386 } 387 }) 388 }) 389 Button("获取选择内容").onClick(() => { 390 this.content = ""; 391 this.controller.getSpans({ 392 start: this.start, 393 end: this.end 394 }).forEach(item => { 395 if(typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'){ 396 this.content += (item as RichEditorImageSpanResult).valueResourceStr; 397 this.content += "\n" 398 } else { 399 this.content += (item as RichEditorTextSpanResult).value; 400 this.content += "\n" 401 } 402 }) 403 }) 404 Button("删除选择内容").onClick(() => { 405 this.controller.deleteSpans({ 406 start: this.start, 407 end: this.end 408 }) 409 this.start = -1; 410 this.end = -1; 411 this.message = "[" + this.start + ", " + this.end + "]" 412 }) 413 } 414 .borderWidth(1) 415 .borderColor(Color.Red) 416 .width("100%") 417 .height("10%") 418 419 Column() { 420 RichEditor(this.options) 421 .onReady(() => { 422 this.controller.addTextSpan("0123456789", 423 { 424 style: 425 { 426 fontColor: Color.Orange, 427 fontSize: 30 428 } 429 }) 430 this.controller.addImageSpan($r("app.media.icon"), 431 { 432 imageStyle: 433 { 434 size: ["57px", "57px"] 435 } 436 }) 437 this.controller.addTextSpan("0123456789", 438 { 439 style: 440 { 441 fontColor: Color.Black, 442 fontSize: 30 443 } 444 }) 445 }) 446 .onSelect((value: RichEditorSelection) => { 447 this.start = value.selection[0]; 448 this.end = value.selection[1]; 449 this.message = "[" + this.start + ", " + this.end + "]" 450 }) 451 .aboutToIMEInput((value: RichEditorInsertValue) => { 452 console.log("---------------------- aboutToIMEInput ----------------------") 453 console.log("insertOffset:" + value.insertOffset) 454 console.log("insertValue:" + value.insertValue) 455 return true; 456 }) 457 .onIMEInputComplete((value: RichEditorTextSpanResult) => { 458 console.log("---------------------- onIMEInputComplete ---------------------") 459 console.log("spanIndex:" + value.spanPosition.spanIndex) 460 console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]") 461 console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]") 462 console.log("value:" + value.value) 463 }) 464 .aboutToDelete((value: RichEditorDeleteValue) => { 465 console.log("---------------------- aboutToDelete --------------------------") 466 console.log("offset:" + value.offset) 467 console.log("direction:" + value.direction) 468 console.log("length:" + value.length) 469 value.richEditorDeleteSpans.forEach(item => { 470 console.log("---------------------- item --------------------------") 471 console.log("spanIndex:" + item.spanPosition.spanIndex) 472 console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]") 473 console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]") 474 if (typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') { 475 console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr) 476 } else { 477 console.log("text:" + (item as RichEditorTextSpanResult).value) 478 } 479 }) 480 return true; 481 }) 482 .onDeleteComplete(() => { 483 console.log("---------------------- onDeleteComplete ------------------------") 484 }) 485 .borderWidth(1) 486 .borderColor(Color.Green) 487 .width("100%") 488 .height("30%") 489 } 490 .borderWidth(1) 491 .borderColor(Color.Red) 492 .width("100%") 493 .height("70%") 494 } 495 } 496} 497``` 498 499 500### 示例2 501 502```ts 503// xxx.ets 504@Entry 505@Component 506struct RichEditorExample { 507 controller: RichEditorController = new RichEditorController() 508 509 // 自定义键盘组件 510 @Builder CustomKeyboardBuilder() { 511 Column() { 512 Grid() { 513 ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => { 514 GridItem() { 515 Button(item + "") 516 .width(110).onClick(() => { 517 this.controller.addTextSpan(item + '', { 518 offset: this.controller.getCaretOffset(), 519 style: 520 { 521 fontColor: Color.Orange, 522 fontSize: 30 523 } 524 }) 525 this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length) 526 }) 527 } 528 }) 529 }.maxCount(3).columnsGap(10).rowsGap(10).padding(5) 530 }.backgroundColor(Color.Gray) 531 } 532 533 build() { 534 Column() { 535 RichEditor({ controller: this.controller }) 536 // 绑定自定义键盘 537 .customKeyboard(this.CustomKeyboardBuilder()).margin(10).border({ width: 1 }) 538 .height(200) 539 .borderWidth(1) 540 .borderColor(Color.Red) 541 .width("100%") 542 } 543 } 544} 545``` 546 547 548