• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:&nbsp;()&nbsp;=&gt;&nbsp;void) | 富文本组件初始化完成后,触发回调。 |
46| onSelect(callback:&nbsp;(value:&nbsp;[RichEditorSelection](#richeditorselection))&nbsp;=&gt;&nbsp;void) | 鼠标左键按下选择,松开左键后触发回调。<br />- value:选中的所有span信息。 |
47| aboutToIMEInput(callback:&nbsp;(value:&nbsp;[RichEditorInsertValue](#richeditorinsertvalue))&nbsp;=&gt;&nbsp;boolean) | 输入法输入内容前,触发回调。<br />- value:输入法将要输入内容信息。|
48| onIMEInputComplete(callback:&nbsp;(value:&nbsp;[RichEditorTextSpanResult](#richeditortextspanresult))&nbsp;=&gt;&nbsp;void) | 输入法输完成输入后,触发回调。<br />- value:输入法完成输入后的文本Span信息。 |
49| aboutToDelete(callback:&nbsp;(value:&nbsp;[RichEditorDeleteValue](#richeditordeletevalue))&nbsp;=&gt;&nbsp;boolean) | 输入法删除内容前,触发回调。 <br />- value:准备删除的内容所在的文本Span信息。|
50| onDeleteComplete(callback:&nbsp;()&nbsp;=&gt;&nbsp;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:&nbsp;[TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br/>color?:&nbsp;[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:&nbsp;[TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br/>color?:&nbsp;[ResourceColor](ts-types.md#resourcecolor)<br/>} | 否 | 设置文本装饰线样式及其颜色。<br />默认值:{<br/>type:&nbsp;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![richeditor](figures/richeditor.gif)
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![customKeyboard](figures/richEditorCustomKeyboard.gif)
548