所以它的值看起来像是这样的:

当然,有些场景下为了方便操作,也提供了转换为 JSON 类型值的 API:

编辑器依赖 contenteditable 属性提供的输入能力以及光标的控制能力。因此,它拥有所有的默认浏览器行为,但是浏览器的默认行为在不同的浏览器厂商实现下存在不同的处理方式,所以我们其大部分默认行为进行了拦截并进行自定义的处理。

比如输入的过程中 beforeinput input , 删除、回车以及快捷键涉及到的 mousedown mouseup click 等事件都会被拦截,并进行自定义的处理。

在对事件进行接管后,编辑器所做的事情就是管理好基于 contenteditable 属性根节点下的所有子节点了,比如插入文本、删除文本、插入图片等等。

综上所述,编辑中的数据结构是一个 DOM 树结构,所有的操作都是对 DOM 树直接进行操作,不是典型的以数据模型驱动视图渲染的 MVC 模式。

节点约束

为了更方便的管理节点,降低复杂性。编辑器抽象化了节点属性和功能,制定了 mark inline block card 4 种类型节点,他们由不同的属性、样式或 html 结构组成,并统一使用 schema 对它们进行约束。

一个简单的 schema 看起来像是这样:

除此之外,还可以描述属性、样式等,比如:

下面这几种节点都符合上面的规则:

但是除了在 color 和 test 已经在 schema 中定义外,其它的属性(background-color、test1)在处理时都会被编辑器过滤掉。

可编辑器区域内的节点通过 schema 规则,制定了 mark inline block card 4 种组合节点,他们由不同的属性、样式或 html 结构组成,并对它们的嵌套进行了一定的约束。

编辑器中值的定义

带 card 的节点是 am-editor 编辑器中自定义的值,card 可以实现异步渲染,可以在 card 中渲染 React 和 Vue,做更多的交互

card 节点主要属性

  • type 卡片类型,block (单独占一行) 或者 inline(嵌入行内)
  • Name 卡片名称与导入的 CodeBlockComponent.cardName 名称一致
  • Value 卡片的值,用于卡片的渲染,值的类型与结构在定义卡片插件时由卡片插件定义和实现 ui 渲染 卡片值是一个 data 字符串 + json ,以上面的代码块为例,解码后是这样的

一个 data 固定字符串后面跟一个 json,json 中 id 由编辑器生成的唯一 id,type 为卡片的类型,与它的属性 type 是一致的。后面的属性由卡片自定义。

我们对一个 json 值进行编码后就可以赋值给卡片了

在 am-editor 中对这类带卡片的自定义值获取和赋值

通过 engine.getValue() 获取的编辑器值在展示的时候需要通过 View 组件渲染。这样渲染的好处是可以还原卡片内的各种交互以及异步渲染,或者异步获取数据等操作体验

静态的 html

Html 相对于卡片那样的值,是无法提供异步渲染、无法使用其它 ui 库,仅仅是静态的 上一段带卡片节点的值,我们通过引擎提供的方法可以获取到以下 html

卡片转换成了静态 html,这样我们可以自己复制到一个.html 中脱离 react、engine 就可以打开了

把一段 html 再还原成带卡片的值也比较容易。实例化 Engine 与卡片一致,区别在于设置值和获取值

JSON 格式

除了以上两种 DOM 节点的值之外,还提供了 JSON 类型的值,JSON 相比较以上两种值会比较跟容易遍历和操作

JSON 格式的值是通过监听编辑区域(contenteditable 根节点)内的 html 结构的变化,使用 MutationObserver 反推出来的。

我们可以通过 engine.model 来访问这个反推出来的数据模型

Element

节点的类型为 Element

Text

文本节点的类型为 Text

同样的我们可以通过编辑器提供的 getJsonValue 和 setJsonValue 对 json 类型的值进行获取和处理

协同编辑

该开源库通过监听编辑区域(contenteditable 根节点)内的 html 结构的变化,使用 MutationObserver 反推数据结构,并通过 WebSocket Yjs 连接交互,实现多用户协同编辑的功能。

特性

  • 开箱即用,提供几十种丰富的插件来满足大部分需求
  • 高扩展性,除了 mark inline block 类型基础插件外,我们还提供 card 组件结合 React Vue 等前端库渲染插件 UI
  • 丰富的多媒体支持,不仅支持图片和音视频,更支持插入嵌入式多媒体内容
  • 支持 Markdown 语法
  • 引擎纯 JavaScript 编写,不依赖任何前端库,插件可以使用 React Vue 等前端库渲染。复杂架构轻松应对
  • 内置协同编辑方案,轻量配置即可使用
  • 兼容大部分最新移动端浏览器