1、前言
之前我有写过一篇《富文本编辑器粘贴 WPS Word 解决方案》,最近 wangeditor5 发布了公测版本,于是作者就尝试给 v5 版本实现这一功能。 更多详情请查看 《国产开源富文本编辑器 wangEditor 新版 公开测试》
2、从 RTF 中提取图片
在上一篇文章《富文本编辑器粘贴 WPS Word 解决方案》中,我提到了将 RTF 中的 二进制/十六进制 图片提取为 base64
。而这一次不仅提供了 base64
数据,同时还提供 File
数据,以供用户可以将图片上传到服务器。
下面是返回给用户的图片实例:
// picture.d.ts
export default class Picture {
/** 该图片类型内置支持解析为 base64 和 File */
parsed: boolean;
/** 图片的文件类型 */
mime: string;
/** 图片的 ArrayBuffer 对象 */
buffer: ArrayBuffer;
/** 图片的 二进制 数据字符串 */
binary: string;
/** 图片配置关键字和图片数据 */
keywords: string[];
/**
* @param keywords 图片配置关键字和图片数据构成的集合
*/
constructor(keywords: string[]);
/**
* 获取图片的 base64 字符串
*/
get base64(): string | null;
/**
* 获取图片的 File 文件对象
*/
get file(): File | null;
}
复制代码
至于解析 RTF
的过程我这里就不赘述了,那就是一个观察规律并根据规律写一段文本处理逻辑代码而已。更多详情请查看 RTF V1.7 规范 中文版。
3、转换 HTML 为 wangeditor5 节点数据结构
文中后续中我将使用 “module
” 代指 “节点数据结构”
3.1、wangeditor5 module
我们先通过官方文档初步了解一下什么是节点数据。
为了便于理解,我将需要的一些节点数据结构进行了提取整合并重命名,如下:
interface EmptyTextModule {
text: ''
}
/**
* #text mark
*/
export interface TextMark {
color?: string
bgColor?: string
fontSize?: string
fontFamily?: string
bold?: true
italic?: true
through?: true
underline?: true
code?: true
sup?: true
sub?: true
}
/**
* #text module
*/
export interface TextModule extends TextMark {
text: string
}
/**
* anchor module
*/
export interface AnchorModule {
type: 'link'
url: string
target?: string
children: TextModule[]
}
/**
* image module.style
*/
interface ImageStyle {
width?: string
height?: string
}
/**
* img module
*/
export interface ImageModule {
type: 'image'
src: string
children: [EmptyTextModule]
alt?: string
href?: string
style?: ImageStyle
}
/**
* h1~6、p 的公共样式
*/
export interface ParagraphMark {
indent?: string
textAlign?: string
lineHeight?: string
}
/**
* h6、p module
*/
export interface ParagraphModule extends ParagraphMark {
type: 'paragraph'
children: (TextModule | AnchorModule | ImageModule)[]
}
/**
* h1~h5 module.type
*/
export type Header = 'header1' | 'header2' | 'header3' | 'header4' | 'header5'
/**
* h1~h5 module
*/
export interface HeaderModule extends ParagraphMark {
type: Header
children: (TextModule | AnchorModule)[]
}
/**
* th、td module
*/
export interface TableCellModule {
type: 'table-cell'
colSpan?: number
rowSpan?: number
children: (TextModule | AnchorModule | ImageModule)[]
}
/**
* tr module
*/
export interface TableRowModule {
type: 'table-row'
children: TableCellModule[]
}
/**
* table module
*/
export interface TableModule {
type: 'table'
withHeader?: boolean // 是否显示表头
fullWidth?: boolean // 是否宽度 100%
children: TableRowModule[]
}
/**
* ul module
*/
export interface ULModule {
type: 'bulleted-list'
children: LIModule[]
}
/**
* ol module
*/
export interface OLModule {
type: 'numbered-list'
children: LIModule[]
}
/**
* li module
*/
export interface LIModule {
type: 'list-item'
children: (TextModule | AnchorModule)[]
}
复制代码
在 v5 中,标题只支持 <h1~5>
,所以我将 <h6>
和 <p>
归类在了一起。而且在这些数据结构中,引用、分割线、代码块儿和视频在 WPS Word 中是没有的,所以可以忽略掉。
3.2、HTML 转 module
在 《富文本编辑器粘贴 WPS Word 解决方案》 一文的示例中我们使用的是 DOMParser
来辅助 HTML
的解析,这里依旧如此。
其实将 HTML
转换为 v5 module
的过程就是将整个 DOM
树拍扁的过程。至于怎么拍扁呢?其实很简单,就是将特殊的标签转换为特定 module
。比如将 <p>
标签转换为 ParagraphModule
,将 <b>
标签转换为 TextModule
中的 bold
属性。
具体的思路如下:
第一步:依赖收集,遍历整个 DOM tree
,将符合条件的树梢节点的 DOM tree
路径进行缓存收集
第二步:将收集的路径集合转换为 v5 module
3.2.1、DEMO
我们先来看一段 HTML 代码:
<div>
<b>
<u>A</u>
<del>B</del>
</b>
<a href="http://baidu.com">
C
<b>D</b>
E
</a>
</div>
复制代码
上面的 DOM 树经依赖收集我们将得到:
[
[<div>, <b>, <u>, A],
[<div>, <b>, <del>, B],
[<div>, <a>, C],
[<div>, <a>, <b>, D],
[<div>, <a>, E],
]
复制代码
然后我们遍历这个二维数组,将 DOM
路径转换为 v5 module
我们将得到:
[
{
type: 'paragraph',
children: [
{ text: 'A', bold: true, italic: true },
{ text: 'B', bold: true, through: true },
],
},
{
type: 'paragraph',
children: [{
type: 'link',
children: [
{ text: 'C' },
{ text: 'D', bold: true },
{ text: 'E' },
]
}],
},
]
复制代码
3.2.2、效果预览
4、最后
虽然初步完成了 DOM tree
到 module
的转换,但是还有一些特殊的情况是无法处理的,可能需要与使用者手动配合才能达到完美的效果。
比如 WPS Word
中的文本框和浮雕文字,它们在 HTML
中是会以图片的形式存在,而在 RTF
中却不是,这必将导致从 RTF
中提取的图片数量比 HTML
中的图片数量少。这个时候我们就需要使用者对图片进行手动定位了,然后抛弃与文本框和浮雕文字所对应的图片。
加入我们
在 wangEditor 官网找到我们的 QQ 群,进群私聊群主。