小程序插入图片

通过EditorContext.insertImage接口可以实现图片的插入:

EditorContext.insertImage({src,width,height,data,
})
如何插入超链接、公式、视频、表格等等?

通过EditorContext.insertCustomBlock应该是可以实现的,具体实现方式我没有了解过,不过我使用的Taro3框架的版本,不支持渲染editor-portal组件。

于是我通过EditorContext.insertImage接口实现了这些功能。

思路是什么?
  1. 首先,渲染层面:公式可以通过Mathjax库渲染成svg图片;超链接可以通过svg图片的形式渲染成文字图片(如果嫌手动生成svg麻烦,也可以通过Mathjax渲染超链接的文字);表格可以通过svg图片的形式渲染成表格图片(如果嫌手动生成svg麻烦,也可以通过Mathjax渲染表格);视频可以渲染一张封面图或者一张默认图片(点击后可以修改视频或者播放视频等)

  2. 然后,数据层面:上述元素都是图片,如何区分。可以通过EditorContext.insertImage中的data字段来保存type类型和相关属性数据,最终会渲染到html的data-custom中去。

  3. 其次,编辑层面:编辑器中删除按钮可以直接删除图片,然后如果实现点击元素,弹出修改窗口,就可以实现上述元素的修改操作(Editor需要关闭show-img-size、show-img-toolbar、show-img-resize这三个参数),所以需要一种方案实现点击能知道点击的是哪个元素。

  4. 最后,生成的HTML:最终生成的HTML字符串中,上述元素都是img,需要通过data-custom中的type字段来还原成对应的HTML字符串。

尝试实践:
插入元素

我以插入超链接为例:

async insertLink() {const { edit_index, link_text, link_url } = this.stateif (edit_index >= 0) {await this.props.getEditorContext().deleteText({index: edit_index,length: 1,})await this.props.getEditorContext().setSelection({index: edit_index,length: 0,})}let link_info = TexUtil.generateTexInfo(`\\underline{${link_text}}`)// console.log(link_info)this.props.getEditorContext().insertImage({extClass: link_info.extClass,src: link_info.src,nowrap: true,alt: link_text,data: {data: WXEditorHelper.encodeDataCustom({type: 'link',href: link_url,text: link_text})},width: link_info.width,height: link_info.height,})console.log('link ext class:', link_info.extClass)this.closeLinkDialog()
}
  1. extClass用于给图片加上class,因为不能设置style,目前只能通过这种方式给图片加样式。像超链接、公式图片,因为需要和文字对齐,需要设置类似于vertical-align: -0.1em这种(Mathjax生成的公式里有对应的属性);然后文字图片需要根据font-size来进行缩放,需要设置类似于width: 3emheight: 1.5em这种。
    因为不能加style,只能通过class实现,所以只能设置类似于class="width-30em height-15em verticalAlign--1em"这种,通过预先设置一堆固定的class,然后xxem放大10倍后进行四舍五入,比如width: 2.45em对应的class就是width-24em。通过这种方式能近似实现。
    我使用的Taro框架,可以通过less预先生成一堆这种类:
@maxWidth: 100;
@maxHeight: 100;
@minVerticalAlign: -100;
@maxVerticalAlign: 100;// 下面width、height、verticalAlign均为公式图片所需样式
// 批量生成宽度样式
.generateWidth(@n) when (@n > 0) {.width-@{n}em {width: (@n / 10em);}.generateWidth(@n - 1);
}.generateWidth(@maxWidth);// 批量生成高度样式
.generateHeight(@n) when (@n > 0) {.height-@{n}em {height: (@n / 10em);}.generateHeight(@n - 1);
}.generateHeight(@maxHeight);// 批量生成对齐样式
.generateVerticalAlign(@n) when (@n > @minVerticalAlign) {.verticalAlign-@{n}em {vertical-align: (@n / 10em);}.generateVerticalAlign(@n - 1);
}.generateVerticalAlign(@maxVerticalAlign);
  1. src的话,超链接、公式、表格等都是svg图片,通过base64处理后传给src字段:
src: `data:image/svg+xml;base64,${base64.encode(svg_str)}`
  1. data字段,用于存入元素的类型和属性等相关数据:
data: {data: WXEditorHelper.encodeDataCustom({type: 'link',href: link_url,text: link_text})
},

这里我自定义了一个WXEditorHelper.encodeDataCustom接口:

static encodeDataCustom(data) {return base64.encode(JSON.stringify(data))
}

处理成base64,防止最终生成的html中data-custom字段在出现转义、解析困难等问题。

svg的生成

svg图片字符串,公式的话可以通过Mathjax生成,超链接可以自己手动生成,或者使用也使用Mathjax。

不过小程序中使用Mathjax,好像直接使用有困难。我用的Taro框架,所以我找了一个react-native的Mathjax库,然后改了一下,用到了小程序中。由于Mathjax比较大,需要进行分包异步加载。

元素点击事件

小程序Editor没有直接提供点击某个元素,触发相关事件的功能。需要自己来实现。

我的实现思路是:给Editor外层加上点击事件,通过解析Editor数据data中的delta字段,遍历所有字符,通过EditorContext.getBounds函数来判断点击的坐标是否在该字符的坐标范围内(图片占一个字符)。因为点击事件中const { x, y } = e.detail的x和y是相对于屏幕左上角,EditorContext.getBounds得到的bounds也是相对于屏幕左上角,所以即使Editor内部有滚动也不影响。

下面是实现代码(对于delta字段解析不太确定是否准确):

getWxDeltaLength(delta) {const { ops } = deltaif (!ops) {return 0}let all_length = 0for (let i = 0; i < ops.length; i++) {let item = ops[i]if (!item.insert) {continue }if (item.insert.image) {all_length += 1 // 图片算一个字符}else {all_length += item.insert.length}}return all_length
}getWxDeltaIndexType(delta, index) {const { ops } = deltaif (!ops) {return {type: 'text',}}let now_index = 0for (let i = 0; i < ops.length; i++) {let item = ops[i]if (!item.insert) {continue }let old_index = now_indexif (item.insert.image) {now_index += 1 // 图片算一个字符}else {now_index += item.insert.length}if (old_index <= index && index < now_index) {if (item.insert.image) {let data_custom = WXEditorHelper.decodeDataCustom(item.attributes['data-custom'])console.log(data_custom)if (data_custom && data_custom.type == 'tex') {return {type: 'tex',data: data_custom,}}if (data_custom && data_custom.type == 'link') {return {type: 'link',data: data_custom,}}if (data_custom && data_custom.type == 'table') {return {type: 'table',data: data_custom,}}return {type: 'image',src: item.insert.image,// width: item.attributes && item.attributes.width ? item.attributes.width : null,data: item.attributes ? data_custom : null,}}else {return {type: 'text'}}}}return {type: 'text'}
}async onClickEditor(e) {const { x, y } = e.detail// console.log(x, y)let data_res = await this.editor_context.getContents()// console.log(data_res)let all_length = this.getWxDeltaLength(data_res.delta)// console.log('all_length:', all_length)// 二分法应该可以优化,规模小暂时不优化for (let i = 0; i < all_length; i++) {let bounds_res = await this.editor_context.getBounds({index: i,length: 1,})let bounds = bounds_res.bounds// console.log(bounds)if (bounds.left <= x && x <= bounds.left + bounds.width &&bounds.top <= y && y <= bounds.top + bounds.height) {// console.log('click on index:', i)let item_type = this.getWxDeltaIndexType(data_res.delta, i)// console.log('click on type:', item_type)if (item_type.type != 'text') {this.onClickItem(i, item_type.type, item_type.data, item_type)}break}}
}
最终html字符串的处理

需要把html中所有的img标签处理成对应的<a></a><span data-formula="" ></span><table></table>等等。

根据data-custom字段,例如data-custom="data=DJLFDSJFLK",提取里面的base64部分,然后解码回去,得到data数据:

static decodeDataCustom(data) {if (!data) {return null}// console.log('decodeCustomData:', data)let data_str = data.substring('data='.length)// console.log(data_str)try {return JSON.parse(base64.decode(data_str))}catch (e) {console.log(e)return null}
}

因为我用的Taro框架,对html转成dom有支持,所以这一部分实现还算简单。如果原生小程序可能需要进行正则匹配然后处理字符串。

此外,Editor导出html是上述的处理方式。导入html也需要对应的反向处理,将<a></a><span data-formula="" ></span><table></table>等等标签,再处理回img标签,此处不再展开。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88004.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88004.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/88004.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

传输层协议TCP、UDP

传输层协议TCP、UDP 1、TCP和UDP报文格式 传输层协议TCPvsUDP 传输层主要两个传输协议&#xff0c;分别是TCP和UDP&#xff0c;负责提供流量控制、排序服务和错误校验。 &#xff08;1&#xff09;TCP是面向连接的&#xff0c;一般用于传输数据量比较少&#xff0c;且对可靠性要…

设计模式—专栏简介

大学总是忙着参加ACM实验室的各种事情&#xff0c;到了毕业的时候&#xff0c;对于设计模式也是仅了解单例模式。毕业后&#xff0c;刚开始代码也是乱写一通&#xff0c;完全没有章法。整个开发环境也是为了解决问题&#xff0c;从来没有考虑结构化什么的&#xff08;没办法&am…

面试150 链表的复制

思路 python可以使用调库法&#xff0c;使用深度拷贝 """ # Definition for a Node. class Node:def __init__(self, x: int, next: Node None, random: Node None):self.val int(x)self.next nextself.random random """class Solution:de…

MySQL分布式ID冲突详解:场景、原因与解决方案

引言 在分布式系统开发中&#xff0c;你是否遇到过这样的崩溃时刻&#xff1f;——明明每个数据库实例的自增ID都从1开始&#xff0c;插入数据时却提示“Duplicate entry ‘100’ for key ‘PRIMARY’”&#xff1b;或者分库分表后&#xff0c;不同库里的订单ID竟然重复&#x…

c++文字游戏_闯关打怪2.0(开源)

本次更新内容: 1.增强对手性能 2.可暂停(按N) 3.修复些许bug 4.增加boos关(第10、20、30...关) 1. 游戏概述 本游戏是一个基于Windows控制台的回合制战斗游戏,采用俯视视角的2D平面设计。玩家控制角色"p"在1325大小的封闭场景中与敌人"@"战斗,通过…

Java学习第十二部分——idea各种项目简介

目录 一.前言 二.语言介绍 三.生成器介绍 四.拓展 一.前言 打开idea项目创建时发现如上情况&#xff0c;“新建项目”下面的是语言&#xff0c;生成器下面的是这些语言对应的生成器工具&#xff0c;本文将简单介绍。 二.语言介绍 Java 用途&#xff1a;Java是一种广泛使…

Codeforces Round 868 (Div. 2) D. Unique Palindromes(1900,构造)

Problem - D - Codeforces 不错的字符串构造体&#xff0c;记录一下 首先注意到k≤20这一条件。对于一个长度为n的字符串&#xff0c;最多有n个不同的回文子串&#xff0c;这种情况出现在所有字符都相同时。因此&#xff0c;限制条件中的xi必须满足xi≤ci&#xff0c;且相邻两…

ClickHouse 全生命周期性能优化

引言 ClickHouse作为列式存储的OLAP数据库&#xff0c;以其极致的查询性能著称&#xff0c;但"高性能"并非开箱即用。不合理的表设计、SQL写法或集群配置&#xff0c;可能导致性能衰减甚至服务不可用。本文基于ClickHouse 24.3版本&#xff0c;从设计规范、开发规范、…

Linux sed 命令 详解

在 Linux 系统中&#xff0c;sed&#xff08;Stream Editor&#xff09;是一个非常强大且灵活的文本处理工具。它不仅可以用于简单的文本替换、删除和插入操作&#xff0c;还能实现复杂的文本转换任务。 &#x1f4cc; 一、什么是 sed&#xff1f; sed 是一个基于模式匹配对文…

项目进度同步不及时,如何提升信息透明度

项目进度同步不及时的核心问题包括沟通渠道不畅通、缺乏统一的信息平台、未建立明确的进度更新机制、团队意识不足、责任划分不明确等。其中&#xff0c;缺乏统一的信息平台最为关键。统一的信息平台能够确保所有相关人员实时掌握最新的进度状态&#xff0c;避免信息孤岛&#…

使用各种CSS美化网页

实验目的1.理解CSS的概念&#xff0c;掌握CSS定义样式的方法&#xff0c;具备使用CSS和相关库进行界面样式设计的能力。 2.掌握Bootstrap 5的基本使用方法。3.Bootstrap框架练习实验步骤1. 实验准备创建一个HTML文件&#xff08;如 index.html&#xff09;。引入Bootstrap5的CS…

在PPT的文本框中,解决一打字,英文双引号就变成中文了

问题&#xff1a;在制作PPT的过程中&#xff0c;插入文本框&#xff0c;在里面输入代码类的格式时&#xff0c;使用英文的双引号""&#xff0c;但是只要在后面输入内容&#xff0c;或者逗号等&#xff0c;英文双引号就变成中文了&#xff0c;很烦原因&#xff1a;大概…

iOS 证书过期如何处理

找到钥匙串位置创建新的CSR文件。点击菜单中钥匙串访问—>证书助理—>从证书颁发机构请求证书…进入证书助理&#xff0c;填写信息&#xff08;用户名称和邮箱随便写&#xff09;&#xff0c;请求是 选择 存储到磁盘创建好CSR文件&#xff0c;回到developer 证书管理中心…

CODESYS + 全志T113-i + 国产系统OneOS,打造新一代工业控制解决方案!

创龙科技与中移物联网有限公司、CODESYS携手合作&#xff0c;成功实现了T113-i工业评估板对国产系统OneOS CODESYS软件的适配&#xff0c;此举将让工业自动化领域的工程师们更高效地开发&#xff0c;并为众多企业产品的快速上市提供强有力的保障。 解决方案简介 CODESYS简介 …

三、jenkins使用tomcat部署项目

一、安装tomcattomcat本来应该是第3台服务器的&#xff08;第一台&#xff1a;gitlab&#xff0c;第二台&#xff1a;jenkins&#xff0c;第三台&#xff1a;tomcat&#xff09;&#xff0c;我这里资源有限&#xff0c;就把tomcat安装jenkins服务器了。#解压tocmcat [rootbogon…

华为eNSP防火墙实验(包含详细步骤)

拓扑图 这里要用的防火墙是 &#xff0c; 需要导入 目录 防火墙配置1&#xff08;启动图形化界面&#xff09; cloud配置 缓冲区服务器配置 防火墙配置2&#xff08;各端口的ip地址&#xff09; 外部路由器配置 本地路由器配置 防火墙配置3&#xff08;配置安全策略&a…

Linux/Unix线程及其同步(create、wait、exit、互斥锁、条件变量、多线程)

线程 文章目录线程I 线程基本概念1、为什么引入线程2、PthreadsII 线程基本操作1、创建线程2、终止线程3、线程ID4、连接已终止线程5、线程基本操作示例III 通过互斥量同步线程1、基本概念2、互斥量&#xff08;Mutex&#xff09;3、静态分配互斥量4、互斥量锁定与解锁5、互斥量…

vue3 el-table 行数据沾满格 取消自动换行

在 Vue.js 使用 Element UI 或 Element Plus 的 <el-table> 组件时&#xff0c;如果你希望其中的单元格内容不自动换行&#xff0c;可以通过设置 CSS 样式来实现。这里有几种方法可以做到这一点&#xff1a;方法1&#xff1a;使用 CSS 样式你可以直接在 <el-table-col…

操作系统级TCP性能优化:高并发场景下的内核参数调优实践

在高并发网络场景中&#xff0c;操作系统内核的TCP/IP协议栈配置对系统性能起着决定性作用。本文聚焦操作系统层面&#xff0c;深入解析内核参数调优策略&#xff0c;帮助读者构建稳定高效的网络通信架构。 一、连接管理参数优化&#xff1a;从三次握手到队列控制 1.1 监听队列…

基于物联网的智能交通灯控制系统设计

标题:基于物联网的智能交通灯控制系统设计内容:1.摘要 摘要&#xff1a;随着城市交通流量的不断增加&#xff0c;传统交通灯控制方式已难以满足高效交通管理的需求。本研究的目的是设计一种基于物联网的智能交通灯控制系统。方法上&#xff0c;该系统利用物联网技术&#xff0c…