• 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| 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:&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| 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:&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/>}。 |
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![richeditor](figures/richeditor.gif)
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![customKeyboard](figures/richEditorCustomKeyboard.gif)
559