Creación del editor de texto enriquecido de alto rendimiento de Flutter - Protocolo

Autor: Free Fish Technology - Vino ligero

Como plataforma de comercio inactivo de segunda mano, Xianyu es particularmente importante para que los vendedores publiquen productos y produzcan suministros de alta calidad; los editores de productos esperan tener capacidades de edición de texto enriquecido, lo que permite a los usuarios producir mejor contenido de una manera simple y conveniente; Flutter mismo no tiene un editor de texto enriquecido, solo el editor de texto más básico, TextField; para escenarios más complejos, como admitir expresiones personalizadas, temas, párrafos ordenados y otras capacidades, el componente flutter actual no puede cumplir con nuestros requisitos comerciales, y además del La experiencia interactiva con Native todavía tiene una cierta brecha; para resolver los problemas anteriores que enfrentamos en el negocio, decidimos diseñar e implementar un editor de texto enriquecido escalable y de alto rendimiento en el escenario de Flutter.

Diseño general de la arquitectura del editor de texto enriquecido

Primero, echemos un vistazo a las capas de diseño de la arquitectura general:

p0

Hay cuatro capas principales de abajo hacia arriba:

  1. 1. Capa de protocolo: principalmente responsable de la definición del modelo, la descripción de la selección, el procesamiento de la lógica de eventos comunes y la verificación de la normalización del protocolo;
  2. 2. Capa de extensión de capacidad: la capa de extensión de capacidad proporciona una gran cantidad de capacidades de complementos, incluidos complementos integrados, como conversión de texto sin formato, deshacer/rehacer y otras capacidades, y también es muy conveniente admitir extensiones personalizadas de la capa comercial. , como el apoyo fuera del sitio El complemento de serialización del modelo a HTML que se muestra en la página H5;
  3. 3. Capa de representación: la capa de representación realiza principalmente la conversión del modelo de texto enriquecido en la representación de Flutter Widget, así como el cálculo y la representación del cursor, la selección, la barra de herramientas, etc., así como los eventos de interacción de gestos del usuario;
  4. 4. Capa de expansión comercial: al comienzo del diseño de Mural, la escalabilidad era una parte muy importante del proceso de diseño. Brindamos a las partes comerciales capacidades de expansión muy flexibles y poderosas. Al personalizar Node, Plugin y Normalizing, podemos lograr como la posibilidad de personalizar expresiones, temas, párrafos, resaltado de sintaxis, etc.;

Diseño de capa de protocolo

Los editores de texto enriquecido no son desconocidos para todos. Hasta ahora, ha habido muchos editores de texto enriquecido de código abierto excelentes; cuando queremos hacer el protocolo de texto enriquecido de Flutter, la primera idea es comprender la excelente solución de editor de texto enriquecido de código abierto para evitar trabajar a puerta cerrada;

En la actualidad, existen editores de texto enriquecido de código abierto relativamente excelentes, como CKEditor, Quill, Prosemirror, Draft, Slate, etc., después de comprender y comparar, decidimos utilizar Slate como protocolo de nuestro editor de texto enriquecido;

¿Por qué Slatejs?

¿Por qué elegimos Slate?

p4

Los complementos son ciudadanos de primera clase y pueden cumplir con nuestros requisitos de escalabilidad, Slatjs admite estructuras anidadas en el diseño, que pueden cumplir con escenarios comerciales complejos;

El mismo modelo de datos que Dom hace que sea más conveniente implementar la capa de renderizado flutter más adelante;

El diseño de instrucciones intuitivas puede admitir muy bien la extensión personalizada del complemento;

En el diseño de Slate, existe una clara división central entre la capa de protocolo y la capa de representación, lo que nos permite reutilizar el diseño de la capa de protocolo de Slate, y la capa de representación se entrega a flutter para su procesamiento;

Además de las razones anteriores, otra razón importante por la que elegimos Slate es la cobertura y la integridad de las pruebas unitarias, lo que nos da más confianza en su estabilidad;

Diseño de capa de protocolo de pizarra

El diseño general de la arquitectura de la capa de protocolo es el siguiente:

arco

Tomemos Slate como ejemplo para ver el diseño de la capa de protocolo del editor de texto enriquecido y los conceptos y módulos centrales que deben definirse:

  1. 1. Definición del modelo anidado;
  2. 2. Capacidad atómica Diseño de operación;
  3. 3. El diseño del mantenedor de pedidos Normalización;

Diseño de capa de protocolo: diseño de modelo anidado

Slate define tres tipos de nodos Node:

  • • Editor: el nodo raíz que contiene todo el contenido del documento;
  • • Elemento: nodo contenedor con semántica en campos personalizados;
  • • Texto: un nodo hoja que contiene el texto del documento;

dom_tree

Editor

La interfaz abstracta del Editor se define de la siguiente manera:

abstract class BaseEditor {
  BaseEditor();
  Selection selection;
  List<Operation> operations;
  Map<dynamic, dynamic> marks;
  
  bool isInline(Element element);
  bool isVoid(Element element);
  void normalizeNode(Tuple2<Node, Path> entry);
  void onChange();
  void addMark(String key, dynamic any);
  void apply(Operation operation);
  void deleteBackward(String unit);
  void deleteForward(String unit);
  void deleteFragment(String direction);
  List<Descendant> getFragment();
  void insertBreak();
  void insertFragment(List<Node> fragment);
  void insertNode(Node node, {Location at});
  void insertText(String text);
  void removeMark(String text);
}
复制代码

Elemento

El nodo Element es especial. Es un nodo Ancentor, que contiene nodos secundarios como un nodo contenedor; también es un nodo Descendente, que puede existir como un nodo secundario de otros nodos contenedores.

  • • Bloques: El elemento por defecto es un nodo de tipo bloque, que es un párrafo independiente, en el diseño del protocolo Slate, no se permite que un párrafo tenga un carácter de nueva línea. Cuando se ingresa un carácter de nueva línea, se generará una nueva línea. Elemento de tipo Bloque;
  • • 行内(Inlines):同时Element也可以是Inline类型的节点,作为另外一个Element的嵌套子节点存在,作为行内元素渲染在一行;
  • • 空元素(Void):Element也可以是Void类型,这里Void与HTML中Void的是同一个概念:如果某个Node为Void,则表示这个Node节点是不可编辑状态,光标无法定位到节点内部,会被整体输入和删除;比如:@某个人、主题、富文本中的图片或者视频等等;

Text

Text节点是树中的最低级叶子节点,描述了文本内容以及其他自定义的渲染元素;所有的自定义属性都包含在properties属性中:

class Text implements Descendant {
  String text;

  Map<String, dynamic> properties;

  Text({@required String text, Map<String, dynamic> properties})
      : this.text = text ?? '',
        this.properties = properties ?? <String, dynamic>{};

  @override
  String string() {
    return text;
  }
  
  @override
  Text clone() {
    return Text(text: text, properties: Map.from(properties));
  }

  @override
  String nativeString() {
    return text;
  }
}
复制代码

我们以下面这这段富文本为例:

p1

最终这样一段富文本对应的Mode定义如下:

6

可以看到,Model的树形结构还是比较简单的,所有的属性都存放在properties字段中,这也非常方便实现自定义扩展;Flutter渲染层根据Node节点的Type以及properties属性,将富文本内容渲染到屏幕上;

协议层设计——原子能力Operation

接下来需要富文本Commond协议的设计,用户的每一次的文字输入、删除、文字加粗、换行等操作都是一次Command指令;Slate抽象定义了九个最基本的Operations,协议层所有的Commond指令,最终在协议层,都会转换成一个或者多个operation操作:

  • • insert_node:插入Node节点;
  • • insert_text:插入文本;
  • • merge_node:合并相同属性的Node节点;
  • • move_node:移动Node;
  • • remove_node:删除Node;
  • • remove_text:删除文本;
  • • set_node:设置Node属性;
  • • set_selection:设置Selection;
  • • split_node:拆分Node;

下面我们通过对选中文本加粗操作为例,来了解Slate协议层Commond的处理过程:

10

对选中文本加粗Para tal Commond, la capa de protocolo desensamblará el Commond en tres operaciones:

  • split_node: divide un nodo de texto en tres nodos de texto;
  • set_selection: Actualizar el área de selección del cursor Selección;
  • set_node: establezca la propiedad negrita de las propiedades del nodo Nodo de texto que debe estar en negrita;

Cuando la capa de protocolo divide un Commond en una o más operaciones, realizará una operación muy importante: la normalización;

Mantenedor de Orden - Normalizando

Cada operación de Comando, en la mayoría de los casos, el Modelo se modificará en consecuencia; necesitamos un mantenedor de orden, Normalización, para garantizar siempre que la estructura de datos sea correcta después de que se haya modificado el Modelo de protocolo;

Slate define varias Normalizingreglas integradas básicas:

p10

Después de cada Commond, el Editor llamará normalizeNodeal método.En el proceso de Normalización, se encuentra que hay un error de estructura de protocolo, que necesita ser reparado;

NormalizingOtra característica poderosa es que podemos personalizar Normalizingy agregar reglas de validación personalizadas para lograr requisitos personalizados, en los siguientes capítulos de expansión comercial, explicaremos específicamente cómo implementar rápidamente una costumbre a través de la normalización personalizada.

Resumir

En la actualidad, Mural se ha implementado en el lanzamiento del producto Xianyu, los detalles del producto, las noticias y otros escenarios, lo que respalda las capacidades comerciales, como expresiones y temas personalizados, y la experiencia del usuario también se ha mejorado considerablemente.

Esta vez, presentaremos principalmente el diseño de arquitectura general del editor de texto enriquecido Mural y el diseño de la capa de protocolo; en el seguimiento, presentaremos el diseño de la capa de representación, el diseño de extensión personalizado y la práctica de optimización de la experiencia interactiva y el rendimiento en una serie de artículos.

Enlace de referencia: [1] Slate: github.com/ianstormtay…

Supongo que te gusta

Origin juejin.im/post/7098927963122434078
Recomendado
Clasificación