安装

介绍

除引擎库纯javascript编写外,我们所提供的插件中,小部分插件 UI 比较复杂,使用前端库来渲染 UI 是一项比较轻松的工作。

下面这三个插件有区别

  • @aomao/toolbar 编辑器工具栏。按钮、图标、下拉框、颜色选择器等都是复杂的 UI

  • @aomao/plugin-codeblock 选择代码语言的下拉框具有搜索功能,使用前端库现有的 UI 是比较好的选择

  • @aomao/plugin-link 链接输入、文本输入,使用前端库现有的 UI 是比较好的选择

Vue2 案例 https://github.com/zb201307/am-editor-vue2

Vue3 案例 https://github.com/red-axe/am-editor-vue

React 案例 https://github.com/yanmao-cc/am-editor/tree/master/examples/react

安装

使用 npm 或者 yarn 安装编辑引擎

  1. $ npm install @aomao/engine
  2. # or
  3. $ yarn add @aomao/engine

使用

我们按从输出一个Hello word!入手。现在你可以在下方编辑了。

  1. /**
  2. * defaultShowCode: true
  3. */
  4. import React, { useEffect, useRef, useState } from 'react';
  5. import Engine, { EngineInterface } from '@aomao/engine';
  6. const EngineDemo = () => {
  7. //编辑器容器
  8. const ref = useRef<HTMLDivElement | null>(null);
  9. //引擎实例
  10. const [engine, setEngine] = useState<EngineInterface>();
  11. //编辑器内容
  12. const [content, setContent] = useState<string>('Hello word!');
  13. useEffect(() => {
  14. if (!ref.current) return;
  15. //实例化引擎
  16. const engine = new Engine(ref.current);
  17. //设置编辑器值
  18. engine.setValue(content);
  19. //监听编辑器值改变事件
  20. engine.on('change', () => {
  21. const value = engine.getValue();
  22. setContent(value);
  23. console.log(`value:${value}`);
  24. });
  25. //设置引擎实例
  26. setEngine(engine);
  27. }, []);
  28. return <div ref={ref} />;
  29. };
  30. export default EngineDemo;

插件

现在我们在上述代码基础上,引入@aomao/plugin-bold加粗插件

```tsx | pure import Bold from ‘@aomao/plugin-bold’;

  1. 然后将`Bold`插件加入引擎
  2. ```tsx | pure
  3. //实例化引擎
  4. const engine = new Engine(ref.current, {
  5. plugins: [Bold],
  6. });

Bold插件的默认快捷键为 windows ctrl+b 或 mac ⌘+b,现在试试加粗效果吧

  1. import React, { useEffect, useRef, useState } from 'react';
  2. import Engine, { EngineInterface } from '@aomao/engine';
  3. import Bold from '@aomao/plugin-bold';
  4. const EngineDemo = () => {
  5. //编辑器容器
  6. const ref = useRef<HTMLDivElement | null>(null);
  7. //引擎实例
  8. const [engine, setEngine] = useState<EngineInterface>();
  9. //编辑器内容
  10. const [content, setContent] = useState<string>(
  11. 'Hello <strong>word</strong>!',
  12. );
  13. useEffect(() => {
  14. if (!ref.current) return;
  15. //实例化引擎
  16. const engine = new Engine(ref.current, {
  17. plugins: [Bold],
  18. });
  19. //设置编辑器值
  20. engine.setValue(content);
  21. //监听编辑器值改变事件
  22. engine.on('change', () => {
  23. const value = engine.getValue();
  24. setContent(value);
  25. console.log(`value:${value}`);
  26. });
  27. //设置引擎实例
  28. setEngine(engine);
  29. }, []);
  30. return <div ref={ref} />;
  31. };
  32. export default EngineDemo;

卡片

卡片是编辑器中单独划分的一个区域,该区域的 UI 可以使用 React、Vue 等前端框架自定义渲染内容,最后再挂载到编辑器上。

引入@aomao/plugin-codeblock代码块插件,这个插件部分 UI 使用前端框架渲染,所以有区分。 vue3开发者使用 @aomao/plugin-codeblock-vue vue2开发者使用 am-editor-codeblock-vue2

```tsx | pure import CodeBlock, { CodeBlockComponent } from ‘@aomao/plugin-codeblock’;

  1. `CodeBlock`插件和`CodeBlockComponent`卡片组件加入引擎
  2. ```tsx | pure
  3. //实例化引擎
  4. const engine = new Engine(ref.current, {
  5. plugins: [CodeBlock],
  6. cards: [CodeBlockComponent],
  7. });

CodeBlock插件默认支持markdown,在编辑器一行开头位置输入代码块语法```javascript回车后,看看效果吧

  1. import React, { useEffect, useRef, useState } from 'react';
  2. import Engine, { EngineInterface } from '@aomao/engine';
  3. import CodeBlock, { CodeBlockComponent } from '@aomao/plugin-codeblock';
  4. const EngineDemo = () => {
  5. //编辑器容器
  6. const ref = useRef<HTMLDivElement | null>(null);
  7. //引擎实例
  8. const [engine, setEngine] = useState<EngineInterface>();
  9. //编辑器内容
  10. const [content, setContent] = useState<string>(
  11. 'Hello <strong>word</strong>!',
  12. );
  13. useEffect(() => {
  14. if (!ref.current) return;
  15. //实例化引擎
  16. const engine = new Engine(ref.current, {
  17. plugins: [CodeBlock],
  18. cards: [CodeBlockComponent],
  19. });
  20. //设置编辑器值
  21. engine.setValue(content);
  22. //监听编辑器值改变事件
  23. engine.on('change', () => {
  24. const value = engine.getValue();
  25. setContent(value);
  26. console.log(`value:${value}`);
  27. });
  28. //设置引擎实例
  29. setEngine(engine);
  30. }, []);
  31. return <div ref={ref} />;
  32. };
  33. export default EngineDemo;

工具栏

引入@aomao/toolbar工具栏,工具栏 UI 比较复杂,都是借助使用前端框架渲染,vue3开发者使用 @aomao/toolbar-vue vue2开发者使用 am-editor-toolbar-vue2

```tsx | pure import Toolbar, { ToolbarPlugin, ToolbarComponent } from ‘@aomao/toolbar’;

  1. `ToolbarPlugin`插件和`ToolbarComponent`卡片组件加入引擎,它将让我们在编辑器中可以使用快捷键`/`唤醒出工具栏
  2. ```tsx | pure
  3. //实例化引擎
  4. const engine = new Engine(ref.current, {
  5. plugins: [ToolbarPlugin],
  6. cards: [ToolbarComponent],
  7. });

渲染工具栏,工具栏已配置好所有插件,这里我们只需要传入插件名称即可

```tsx | pure return ( … { engine && ( ) } … )

  1. ```tsx
  2. /**
  3. * transform: true
  4. */
  5. import React, { useEffect, useRef, useState } from 'react';
  6. import Engine, { EngineInterface } from '@aomao/engine';
  7. import Bold from '@aomao/plugin-bold';
  8. import CodeBlock, { CodeBlockComponent } from '@aomao/plugin-codeblock';
  9. import Toolbar, { ToolbarPlugin, ToolbarComponent } from '@aomao/toolbar';
  10. const EngineDemo = () => {
  11. //编辑器容器
  12. const ref = useRef<HTMLDivElement | null>(null);
  13. //引擎实例
  14. const [engine, setEngine] = useState<EngineInterface>();
  15. //编辑器内容
  16. const [content, setContent] = useState<string>(
  17. 'Hello <strong>word</strong>!',
  18. );
  19. useEffect(() => {
  20. if (!ref.current) return;
  21. //实例化引擎
  22. const engine = new Engine(ref.current, {
  23. plugins: [CodeBlock, Bold, ToolbarPlugin],
  24. cards: [CodeBlockComponent, ToolbarComponent],
  25. });
  26. //设置编辑器值
  27. engine.setValue(content);
  28. //监听编辑器值改变事件
  29. engine.on('change', () => {
  30. const value = engine.getValue();
  31. setContent(value);
  32. console.log(`value:${value}`);
  33. });
  34. //设置引擎实例
  35. setEngine(engine);
  36. }, []);
  37. return (
  38. <>
  39. {engine && <Toolbar engine={engine} items={[['bold']]} />}
  40. <div ref={ref} />
  41. </>
  42. );
  43. };
  44. export default EngineDemo;

自己开发工具栏

@aomao/toolbar 更多的是提供了一个工具栏的 UI 展示,本质是调用 engine.command.execute 执行插件命令

  1. /**
  2. * transform: true
  3. */
  4. import React, { useEffect, useRef, useState } from 'react';
  5. import Engine, { EngineInterface } from '@aomao/engine';
  6. import Bold from '@aomao/plugin-bold';
  7. const EngineDemo = () => {
  8. //编辑器容器
  9. const ref = useRef<HTMLDivElement | null>(null);
  10. //引擎实例
  11. const [engine, setEngine] = useState<EngineInterface>();
  12. //编辑器内容
  13. const [content, setContent] = useState<string>(
  14. 'Hello <strong>word</strong>!',
  15. );
  16. // 按钮状态
  17. const [btnActive, setBtnActive] = useState<boolean>(false);
  18. useEffect(() => {
  19. if (!ref.current) return;
  20. //实例化引擎
  21. const engine = new Engine(ref.current, {
  22. plugins: [Bold],
  23. });
  24. //设置编辑器值
  25. engine.setValue(content);
  26. //监听编辑器值改变事件
  27. engine.on('change', () => {
  28. const value = engine.getValue();
  29. setContent(value);
  30. console.log(`value:${value}`);
  31. });
  32. // 监听光标改变
  33. engine.on('select', () => {
  34. // 查询bold插件的选中状态
  35. setBtnActive(engine.command.queryState('bold'));
  36. });
  37. //设置引擎实例
  38. setEngine(engine);
  39. }, []);
  40. const handleMouseDown = (event: React.MouseDown) => {
  41. // 点击按钮避免编辑器光标丢失
  42. event.preventDefault();
  43. };
  44. const handleBoldClick = () => {
  45. // 执行加粗命令
  46. engine?.command.execute('bold');
  47. };
  48. return (
  49. <>
  50. {engine && (
  51. <button
  52. onMouseDown={handleMouseDown}
  53. onClick={handleBoldClick}
  54. style={{ color: btnActive ? 'blue' : '' }}
  55. >
  56. Bold
  57. </button>
  58. )}
  59. <div ref={ref} />
  60. </>
  61. );
  62. };
  63. export default EngineDemo;

协同编辑

协同编辑基于ShareDB实现。每位编辑者作为客户端通过WebSocket服务端通信交换数据。编辑器处理数据、渲染数据。

我们需要把服务端搭建好,然后配置客户端。查看完整示例

tsx | pure //实例化协作编辑客户端,传入当前编辑器引擎实例 const otClient = new OTClient(engine); //连接到协作服务端,uid这里做一个简单的身份验证演示,正常业务中应该需要token等身份验证信息。`demo` 是文档的唯一编号 otClient.connect( `ws://127.0.0.1:8080${currentMember ? '?uid=' + currentMember.id : ''}`, 'demo', );