Lexical 概念

介绍

  • 可扩展的 JavaScript Web 文本编辑器框架
  • 原理:一个contentEditable的元素

主要概念

Editor instances

  • 将所有内容连接在一起的核心
  • 使用createEditor()创建,使用框架绑定时,@lexical/react会自动处理

Editor States

  • 底层数据模型,包含两部分
    • a Lexical node tree
    • a Lexical selection object
  • 创建之后不可变,需通过editor.update(() => {...})更新编辑器状态
  • 获取当前编辑器状态:editor.getEditorState()
  • 编辑器状态可以完全序列化为 JSON,再使用editor.parseEditorState()序列化回编辑器

Editor Updates

  • 当您想要更改编辑器状态中的某些内容时,必须通过更新来完成editor.update(() => {...})
  • 拥有 active editor state 的完整“lexical”上下文
  • 公开了对底层编辑器状态节点树的访问

DOM Reconciler

  • Lexical 有自己的 DOM Reconciler,它采用一组 Editor States(始终是“current”和“pending”)并对它们应用“diff”。然后,使用此 diff 来仅更新 DOM 中需要更改的部分。

Listeners, Node Transforms and Commands

  • 除了调用更新之外,Lexical 完成的大部分工作都是通过 Listeners、Node Transforms 和 Commands 完成的。
const unregisterListener = editor.registerUpdateListener(({editorState}) => {
  // An update has occurred!
  console.log(editorState);
});

// Ensure we remove the listener later!
unregisterListener();
  • Commands 命令是 Lexical 中用于将所有内容连接在一起的通信系统
  • Custom commands
    1. 创建自定义 commands :createCommand() ,并分派到编辑器中:editor.dispatchCommand(command, payload)
    2. 处理 commands:editor.registerCommand(handler, priority)

如何独立于任何框架或库使用 Lexical

Creating an editor and using it

  • 编辑器实例可以被认为是负责将 EditorState 与 DOM 连接起来的实例。
  • 编辑器也是您可以注册自定义节点、添加侦听器和转换的地方
import {createEditor} from 'lexical';

// 创建编辑器实例
const config = {
  namespace: 'MyEditor',
  theme: {
    ...
  },
  onError: console.error
};
const editor = createEditor(config);

// 将编辑器实例与 a content editable <div> element 关联起来
const contentEditableElement = document.getElementById('editor');
editor.setRootElement(contentEditableElement);

// 从元素中清除编辑器实例
// editor.setRootElement(null)

Working with Editor States

  • 调用editor.getEditorState()获取编辑器状态,也可对其序列化和反序列化
const stringifiedEditorState = JSON.stringify(editor.getEditorState().toJSON());
const newEditorState = editor.parseEditorState(stringifiedEditorState);

Updating an editor

有几种方法可以更新编辑器实例(异步过程):

  • editor.update()
  • editor.setEditorState()
  • editor.registerNodeTransform()
  • editor.registerCommand(EXAMPLE_COMMAND, () => {...}, priority)
import {$getRoot, $getSelection, $createParagraphNode, $createTextNode} from 'lexical';

// Inside the `editor.update` you can use special $ prefixed helper functions.
// These functions cannot be used outside the closure, and will error if you try.
// (If you're familiar with React, you can imagine these to be a bit like using a hook
// outside of a React function component).
editor.update(() => {
  // Get the RootNode from the EditorState
  const root = $getRoot();

  // Get the selection from the EditorState
  const selection = $getSelection();

  // Create a new ParagraphNode
  const paragraphNode = $createParagraphNode();

  // Create a new TextNode
  const textNode = $createTextNode('Hello world');

  // Append the text node to the paragraph
  paragraphNode.append(textNode);

  // Finally, append the paragraph to the root
  root.append(paragraphNode);
});

如果您想知道编辑器何时更新以便对更改做出反应,可以向编辑器添加更新侦听器,如下所示:

editor.registerUpdateListener(({editorState}) => {
  // The latest EditorState can be found as `editorState`.
  // To read the contents of the EditorState, use the following API:

  editorState.read(() => {
    // Just like editor.update(), .read() expects a closure where you can use
    // the $ prefixed helper functions.
  });
});
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容