Editor 富文本编辑器

介绍

Editor 富文本编辑器动态库提供了支持富文本编辑的editor组件和操作editor组件的createEditorContext方法,通过使用该动态库,用户可以对图片、文本进行编辑。编辑器导出内容支持带标签的html和纯文本的text,编辑器内部采用delta格式进行存储。

富文本编辑器组件中设置了一些基本样式使得内容可以正确展示,在开发过程中可以进行覆盖,在其他组件或者环境中使用富文本编辑器导出的html时,需要额外维护以下DOM结构:

  1. <ql-container>
  2. <ql-editor></ql-editor>
  3. </ql-container>

使用方法

1. 在项目中引用动态库

参考使用动态库中提供的方法,在app.json中增添一项dynamicLib,与pages同级。

  • JSON
  1. "dynamicLib": {
  2. "editorLib": {
  3. "provider": "swan-editor"
  4. }
  5. },

2. 在使用到富文本编辑器组件的页面配置动态库

在每个使用到富文本编辑器组件的页面,配置*.json文件如:

  • JSON
  1. {
  2. "usingSwanComponents": {
  3. "editor": "dynamicLib://editorLib/editor"
  4. }
  5. }

3. 编写*.swan文件

  • SWAN
  1. <editor
  2. read-only="{{readOnly}}"
  3. placeholder="{{placeholder}}"
  4. />

这是一种最基本的使用方式,其中readOnlyplaceholder的值可以在*.js文件中设置。

  • JS
  1. Page({
  2. data: {
  3. readOnly: false,
  4. placeholder: '请输入...'
  5. }
  6. });

Editor 组件属性列表

属性类型默认值必填说明
read-onlyBooleanfalse设置编辑器为只读
placeholderString编辑器提示信息
show-img-sizeBooleanfalse点击图片时显示图片大小控件
show-img-resizeBooleanfalse点击图片时显示图片缩放控件
show-img-toolbarBooleanfalse点击图片时显示图片工具栏控件
bindreadyEventHandle编辑器初始化完成时触发
bindfocusEventHandle编辑器聚焦时触发,event.detail = { html, text, delta }
bindblurEventHandle编辑器失去焦点时触发,event.detail = { html, text, delta }
bindinputEventHandle编辑器内容改变时触发,event.detail = { html, text, delta }
bindstatuschangeEventHandle编辑器内容或样式通过EditorContext中的方法改变时触发,返回选区已设置的样式

编辑器内支持部分HTML标签和内联样式,但不支持classid

支持的标签

不满足的标签会被忽略,div标签会被转换为p标签存储。

类型节点
行内元素<span><strong> <b> <em> <i> <u> <a> <s> <sub> <sup> <img>
块级元素<br> <hr> <ol> <ul> <li> <h1> <h2> <h3> <h4> <h5> <h6>

支持的内联样式

内联样式仅支持设置在行内元素或块级元素上,不能同时设置,如text-align归类为块级样式,在span标签上设置是无效的。

类型样式
块级样式text-align、direction
行内样式color、background-color

EditorContext 实例

Editor 富文本编辑器动态库提供了createEditorContext的方法来获取某个editor组件的实例,EditorContext通过id和一个editor组件绑定,操作对应的editor组件。

使用方法

  • JS
  1. Page({
  2. onEditorReady() {
  3. this.editorCtx = requireDynamicLib('editorLib').createEditorContext('editorId');
  4. }
  5. });

EditorContext.blur(Object object)

解释:编辑器失焦。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.clear(Object object)

解释:清空编辑器内容。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.format(String name, String value)

解释:修改格式。

对已经应用样式的选区设置会取消样式。

参数

String name:属性

String value:值

支持设置的样式列表

namevalue
bold
italic
underline
strike
ins
scriptsub / super
headerH1 / H2 / H3 / H4 / H5 / H6
aligncenter / right / justify
directionrtl
indent-1 / +1
listordered / bullet / check
colorhex color
backgroudColorhex color

EditorContext.getContents(Object object)

解释:获取编辑器内容。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

object.success 回调函数

参数:Object res

属性类型说明
htmlString带标签的html内容
textString纯文本内容
deltaObject描述内容的delta对象

EditorContext.getSelectionText(Object object)

解释:获取编辑器内选区的纯文本内容。当编辑器失焦或未选中一段区间时,返回内容为空。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

object.success 回调函数

参数:Object res

属性类型说明
textString纯文本内容

EditorContext.insertDivider(Object object)

解释:插入分隔符。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.insertImage(Object object)

解释:插入图片。

参数:Object object

属性类型默认值必填说明
srcString图片地址,目前仅支持 http(s)、base64、本地图片
altString图片无法显示时的替代文本
extClassString添加到图片 img 标签上的类名
dataObjectdata 会被序列化为name1=value1&name2=value2的格式挂在属性 data-custom 上
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.insertText(Object object)

解释:覆盖当前选区,设置一段文本。

参数:Object object

属性类型默认值必填说明
textString文本内容
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.removeFormat(Object object)

解释:清除当前选区的样式。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.setContents(Object object)

解释:初始化编辑器内容,htmldelta同时存在时仅delta生效。

需要注意的是,通过setContents设置编辑器内容时,由于支持的html标签和内联样式有限,建议开发者在小程序内通过delta进行插入。

参数:Object object

属性类型默认值必填说明
htmlString带标签的html内容
deltaObject描述内容的delta对象
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.scrollIntoView()

解释:将编辑器光标处滚动到窗口可视区域内。

EditorContext.redo(Object object)

解释:恢复。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

EditorContext.undo(Object object)

解释:撤销。

参数:Object object

属性类型默认值必填说明
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

示例

在开发者工具中打开

在开发者工具中打开

在 WEB IDE 中打开

扫码体验

代码示例

百度智能小程序

请使用百度APP扫码

图片示例

Editor 富文本编辑器 - 图2

  • SWAN
  • JS
  • CSS
  1. <view class="toolbar" catchtouchend="format">
  2. <view class="iconfont icon-image" catchtouchend="insertImage"></view>
  3. <view class="iconfont icon-format-header-1 {{formats.header === 1 ? 'ql-active' : ''}}" data-name="header" data-value={{1}}></view>
  4. <view class="iconfont icon-format-header-2 {{formats.header === 2 ? 'ql-active' : ''}}" data-name="header" data-value={{2}}></view>
  5. <view class="iconfont icon-format-bold {{formats.bold ? 'ql-active' : ''}}" data-name="bold"></view>
  6. <view class="iconfont icon-format-italic {{formats.italic ? 'ql-active' : ''}}" data-name="italic"></view>
  7. <view class="iconfont icon-format-list {{formats.list === 'checked' ? 'ql-active' : ''}}" data-name="list" data-value="checked"></view>
  8. <view class="iconfont icon-divider" catchtouchend="insertDivider"></view>
  9. <view class="iconfont icon-clear" catchtouchend="clear"></view>
  10. </view>
  11. <view class="editor-wrap">
  12. <editor
  13. id="editorId"
  14. class="editor"
  15. placeholder="开始输入..."
  16. bindready="onEditorReady"
  17. bindstatuschange="onStatusChange"
  18. show-img-size
  19. show-img-resize
  20. show-img-toolbar
  21. />
  22. </view>
  1. const INIT_CONTENT_HTML = `
  2. <p>支持插入图片</p>
  3. <br>
  4. <p>
  5. <img src="https://b.bdstatic.com/searchbox/icms/searchbox/img/editor-image-demo.png" data-custom="id=abcd&amp;role=god" alt="image-alt" class="imageCls" width="100%">
  6. </p>
  7. <hr>
  8. <p>支持以下字符样式</p>
  9. <p>
  10. <b>bold粗体</b>
  11. <em>italic斜体</em>
  12. <u>underline下划线</u>
  13. </p>
  14. <p>
  15. <sub>sub下标</sub>
  16. <sup>super上标</sup>
  17. </p>
  18. <hr>
  19. <p>支持以下列表样式</p>
  20. <ol>
  21. <li>有序列表</li>
  22. <li>有序列表</li>
  23. </ol>
  24. <ul>
  25. <li>无序列表</li>
  26. </ul>
  27. <ul>
  28. <li>无序列表</li>
  29. </ul>
  30. <ul data-checked="true">
  31. <li>选框列表</li>
  32. </ul>
  33. <ul data-checked="false">
  34. <li>选框列表</li>
  35. </ul>
  36. <hr>
  37. <p>支持以下字符大小</p>
  38. <h1>H1 一级标题</h1>
  39. <h2>H2 二级标题</h2>
  40. <h3>H3 三级标题</h3>
  41. <h4>H4 四级标题</h4>
  42. <h5>H5 五级标题</h5>
  43. <h6>H6 六级标题</h6>
  44. <hr>
  45. <p>支持以下对齐方式</p>
  46. <p style="text-align:center">center中间对齐</p>
  47. <p style="text-align:right">right 右对齐</p>
  48. <p style="text-align:justify">justify 自动对齐</p>
  49. <hr>
  50. <span style="color:#00bc89;background-color:#333">color 支持设置字体及背景颜色</span>`;
  51. Page({
  52. data: {
  53. formats: {}
  54. },
  55. // 编辑器初始化完成时触发的事件,用于加载编辑器初始内容
  56. onEditorReady() {
  57. this.editorCtx = requireDynamicLib('editorLib').createEditorContext('editorId');
  58. this.initContent();
  59. },
  60. // 设置编辑器初始内容
  61. initContent() {
  62. this.editorCtx.setContents({
  63. html: INIT_CONTENT_HTML
  64. });
  65. },
  66. // 编辑器内插入图片函数
  67. insertImage() {
  68. const editorCtx = this.editorCtx;
  69. swan.chooseImage({
  70. count: 1,
  71. success: res => {
  72. editorCtx.insertImage({
  73. src: res.tempFilePaths[0],
  74. alt: '插入图片',
  75. data: {
  76. id: 'insert-image',
  77. role: 'user'
  78. },
  79. success: () => {
  80. swan.showToast({
  81. title: '插入图片成功'
  82. });
  83. },
  84. fail: err => {
  85. swan.showToast({
  86. title: '插入图片失败',
  87. icon: 'none'
  88. });
  89. }
  90. });
  91. }
  92. });
  93. },
  94. /**
  95. * 更改编辑器选区为不同格式
  96. *
  97. * @param {Object} e.target.dataset 获取 swan 页面的传参:name、value
  98. *
  99. */
  100. format(e) {
  101. const {name, value} = e.target.dataset;
  102. if (!name) {
  103. return;
  104. }
  105. this.editorCtx.format(name, value);
  106. },
  107. /**
  108. * 编辑器内容或样式通过方法改变时触发的事件,返回选区已设置的样式
  109. *
  110. * @param {Object} e.detail 事件对象
  111. *
  112. */
  113. onStatusChange(e) {
  114. const formats = e.detail;
  115. this.setData({
  116. formats
  117. });
  118. },
  119. // 编辑器中插入分隔符
  120. insertDivider() {
  121. this.editorCtx.insertDivider();
  122. },
  123. // 清除编辑器中内容,与工具栏的垃圾桶图标对应
  124. clear() {
  125. const editorCtx = this.editorCtx;
  126. swan.showModal({
  127. title: '清空编辑器',
  128. content: '确定清空编辑器全部内容?',
  129. success: res => {
  130. if (res.confirm) {
  131. editorCtx.clear();
  132. }
  133. }
  134. });
  135. }
  136. });
  1. @font-face {
  2. font-family: "iconfont"; /* project id 2000141 */
  3. src: url(http://at.alicdn.com/t/font_2000141_vma36b09h9.wof) format("woff"),
  4. url(http://at.alicdn.com/t/font_2000141_vma36b09h9.ttf) format("truetype"),
  5. url(http://at.alicdn.com/t/font_2000141_vma36b09h9.svg#iconfont) format("svg");
  6. }
  7. .iconfont {
  8. display: inline-block;
  9. font-size: 22px;
  10. width: 30px;
  11. height: 30px;
  12. font-family: "iconfont" !important;
  13. font-style: normal;
  14. -webkit-font-smoothing: antialiased;
  15. -moz-osx-font-smoothing: grayscale;
  16. }
  17. .icon-image:before {
  18. content: "\e60e";
  19. }
  20. .icon-format-header-1:before {
  21. content: "\e610";
  22. }
  23. .icon-format-header-2:before {
  24. content: "\e60f";
  25. }
  26. .icon-format-bold:before {
  27. content: "\e60a";
  28. }
  29. .icon-format-list:before {
  30. content: "\e60b";
  31. }
  32. .icon-divider:before {
  33. content: "\e609";
  34. }
  35. .icon-clear:before {
  36. content: "\e60c";
  37. }
  38. .icon-format-italic:before {
  39. content: "\e60d";
  40. }
  41. .editor-wrap {
  42. width: 100%;
  43. height: 100vh;
  44. }
  45. .editor {
  46. display: block;
  47. box-sizing: border-box;
  48. width: 100%;
  49. height: 100%;
  50. margin-top: 50px;
  51. padding: 38.043rpx 30.797rpx;
  52. }
  53. swan-editor {
  54. display: block;
  55. }
  56. .ql-editor {
  57. height: 100%;
  58. }
  59. .toolbar {
  60. position: fixed;
  61. box-sizing: border-box;
  62. padding: 17px 17px;
  63. width: 100%;
  64. height: 45px;
  65. top: 30;
  66. left: 0;
  67. border-top: .906rpx solid #e6e6e6;
  68. border-bottom: .906rpx solid #e6e6e6;
  69. display: flex;
  70. align-items: center;
  71. justify-content: space-between;
  72. background-color: #fff;
  73. z-index: 99;
  74. }
  75. .ql-active {
  76. color: #3388ff;
  77. }