小程序富文本Editor插入圖片、超鏈接、公式等的一次嘗試

小程序插入圖片

通過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…