Implementation plan (under revision)

Interactive process

image-20210619163348259

Analysis

The general structure of slate-ng:

image-20210619172253182

From the figure, we can see the general structure of slate-ng. In slate-ng, each Slate Node is regarded as a Component, assembled into Component Portal according to certain requirements, and mounted to the corresponding position for rendering and display. The core point here lies in the logic under Children. Here are a few points involved:

- How to get the components corresponding to each node?

- How to deal with the component and its children corresponding to each node?

- How to pass the context to each dynamic component?

- How to optimize the treatment plan?

Then let's go over it bit by bit:

1. How to get the components corresponding to each node ?

The approach here is different from react, react in by renderElement,renderLeaf, renderPlaceholder are transmitted to the inner components for processing, but we cannot enjoy the benefits of this approach in slate-ng. So I simplified it to the following transmission and storage (there will be some differences in the implementation of slate-ng as follows, see registry-ns-element:

   // default store value
   const defaultStore = {
      default: DefalutElementComponent,
      text: TextComponent,
      leaf: LeafComponent,
      placeholder: PlaceholderComponent
   }

   // create a new Component corresponding to Node
   @Component({...})
   export class ComponentA {
      static type = 'A' // node component flag
   }

   // use service to register
   this.registryService.add([ComponentA, ComponentB])

   // the final store
   const store = {
      ...defaultStore,
      A: ComponentA
   }

   // Obtain directly from the object according to the type

2. How to deal with the component and its children corresponding to each node?

Here I refer to some processing methods of react use-children and create a children component used to recursively traverse the editor data to assemble a complete portal. The code is as follows (simplified code):

```
resolvePortals(pNode: Ancestor): Array<ComponentPortal<any>> {
   const children = [];
   const editor = this.editorService.editor;
   // ...
   for (let i = 0; i < pNode.children.length; i++) {
      const cNode = pNode.children[i] as Ancestor | Descendant;
      // ...
      let childPortals = [];
      let portal = null;
      if ((cNode as Ancestor).children) {
        childPortals = this.resolvePortals(cNode as Ancestor); // Important!
      }
      // Store childProtals through Injector
      const providers = [
         {provide: CHILD_PORTALS_TOKEN, useValue: childPortals } 
         // ...
      ];
      // ...
      portal = new ComponentPortal(this.regsitorService.get(type), injector.create(providers, this.injector));
      children.push(portal);
   }
   return children;
}

// portals
[
   ComponentPortalA,
   ComponentPortalB,
   ...
]
```

You may find it strange, where is the content of child? This involves the knowledge of ComponentPortal Injector, which is also mentioned in the previous annotations. That is to say, each ComponentPortal actually carries its childPortals, you The output of protals can be understood as such a structure (the real structure is definitely not the case, but you can roughly understand that we have such a general structure):

   [
        ComponentPortalA: {
             injector: {
                child_token: [
                   ComponentPortalA0,
                   ComponentPortalA1
                ]            
             }
        },
        ComponentPortalB
   ]

Finally, we put it in html for processing and rendering:

   <ng-container *ngFor="let portal of showPortals;">
     <ng-template [cdkPortalOutlet]="portal"></ng-template>
   </ng-container>

3. How to pass the context to each dynamic component ?

In fact, we also involved in the second point, that is, Component allows passing injector, we pass the required content through Injector.create(providers, this.parentInjector)

4. How to optimize the treatment plan ?

There is a problem here, because we will create a new ComponentPortal every time, but be careful, suppose we have a sequence, the structure is as follows:

   {
      type: 'list',
      children: [
        {
           type: 'li',
           ...
        }
      ]
   }

If you perform a sequence addition operation, it will add a li to children, and a new ComponentPortal will be recreated every time in the previous processing, which means that we need to complete a small change Re-rendering, this is a very high performance problem, so we need to do caching, we only need to make the changed node recreate a new portal, and the others continue to use the previous ones, code address

Copyright all right reserved,powered by Gitbook该文件修订时间: 2021-06-23 09:50:49

results matching ""

    No results matching ""