微信小程序中可以使用 editor 组件进行富文本编辑,但在钉钉小程序中还没有类似组件可以使用。

相信程序员大都实现过在 web 页面上进行富文本编辑,那么是不是可以通过小程序的 webview 进行嵌入 H5 页面实现呢?

答案是肯定的,如下便是笔者实现的效果图。

富文本编辑器 python 钉钉富文本编辑器_前端


实现这个页面主要难点在于图片的选择和富文本的初始化数据,其他像富文本样式功能的渲染和在 web 中的使用一样。

h5 富文本页面

首先准备一个 web 网页,这个页面上实现富文本编辑器的布局,以及如上图的 “确定” 按钮。我在这里使用的是 wangEditor 这个富文本插件,相关的使用教程大家可以自己去百度,也可以使用自己熟悉的插件。

但需要注意的是要自定义图片点击事件,以便调用小程序图片选择api。

webview 网页和小程序之间的通信可以参考钉钉文档:
https://open.dingtalk.com/document/orgapp-client/web-view

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
		<title></title>
		<script src="./js/wangEditor.js"></script>
		<script src="https://appx/web-view.min.js"></script>
		<style>
			.cu-btn {
				position: relative;
				border: 0rpx;
				display: inline-flex;
				align-items: center;
				justify-content: center;
				box-sizing: border-box;
				padding: 0 15px;
				font-size: 14px;
				width: 100%;
				height: 50px;
				line-height: 1;
				text-align: center;
				text-decoration: none;
				overflow: visible;
				margin-left: initial;
				transform: translate(0rpx, 0rpx);
				margin-right: initial;
				border-radius: 5px;
				background-color: #11a983;
				color: #fff;
				border: none;
			}
			.w-e-icon-fullscreen{
				display: none !important;
			}
			.cu-btn::after {
				display: none;
			}
			#div1 img{
				max-width: 100%;
			}
		</style>
	</head>
	<body style="padding:10px;">
		<div id="div1"></div>
		<div style="padding-top:20px;">
			<button class="cu-btn" type="button" onclick="confirm()">确定</button>
		</div>
		<script type="text/javascript">
			const E = window.wangEditor
			const {
				$,
				BtnMenu,
				DropListMenu,
				PanelMenu,
				DropList,
				Panel,
				Tooltip
			} = E

			class AlertMenu extends BtnMenu {
				constructor(editor) {
					const $elem = E.$(
						`<div class="w-e-menu" data-title="图片">
			                <i class="w-e-icon-image"></i>
			            </div>`
					)
					super($elem, editor)
				}
				// 菜单点击事件
				clickHandler() {
					dd.postMessage({
						ev: 'img'
					})
				}
				tryChangeActive() {
					this.active()
				}
			}
			const menuKey = 'alertMenuKey'

			// 注册菜单
			E.registerMenu(menuKey, AlertMenu)

			const editor = new E('#div1')
			editor.config.menuTooltipPosition = 'down'
			editor.config.menus = [
				'bold',
				'italic',
				'strikeThrough',
				'underline',
				'quote'
			]
			editor.create()
			
			dd.postMessage({ init: true })
			dd.onMessage = function(e) {
				if (e.content) {
					editor.txt.html(e.content)
				} else if (e.img) {
					editor.txt.append("<p><img src='" + e.img +"' /></p>")
				}
			}

			function confirm() {
				dd.postMessage({
					content: editor.txt.html()
				})
			}
		</script>
	</body>
</html>

小程序 webview

建立页面 editor。

在 editor.axml 中使用 webview 组件。

<web-view id="web-view-11" src="{{src}}" onMessage="test"></web-view>

editor.js,使用 app.globalData.content 全局变量存储富文本初始化数据,及完成编辑后的数据。

let app = getApp();
const util = require('/utils/util.js')

Page({
  data: {
    src: '', // h5 页面网址
    action: '' // 图片上传接口
  },
  onLoad() {
    let action = '图片上传接口';
    this.webViewContext = dd.createWebViewContext('web-view-11');
    this.setData({
      action,
      src: `h5 页面网址`
    }, () => {
      dd.showLoading({
        content: '请稍候...'
      })
    })
  },
  test(e) {
    if (e.detail.init) {
      dd.hideLoading();
      this.webViewContext.postMessage({ 'content': app.globalData.content }); //  富文本初始化数据
    } else if (e.detail.ev == 'img') {
      let action = this.data.action;
      let token = '***';
      let self = this;
      // 上传图片
      dd.chooseImage({
        count: 1,
        success: (res) => {
          dd.uploadFile({
            url: action,
            header: { token },
            fileType: 'image',
            fileName: 'file',
            filePath: res.filePaths[0],
            success: (r) => {
              if (r.statusCode == 200 && r.data) {
                let result = JSON.parse(r.data)
                if (result.success) {
                  self.webViewContext.postMessage({ 'img': result.data.outFilePath[0] });
                }
              }
            },
          });
        },
      });
    } else {
      app.globalData.content = e.detail.content;
      dd.navigateBack();
    }
  }
});