Conceptos
Serializando
9 min
el modelo de datos de slate ha sido construido con la serialización en mente específicamente, sus nodos de texto están definidos de una manera que los hace más fáciles de leer de un vistazo, pero también fáciles de serializar a formatos comunes como html y markdown y, dado que slate utiliza json plano para sus datos, puedes escribir lógica de serialización muy fácilmente texto plano por ejemplo, tomando el valor de un editor y devolviendo texto plano import { node } from 'slate' const serialize = nodes => { return nodes map(n => node string(n)) join('\n') } aquí estamos tomando los nodos hijos de un editor como un nodos argumento, y devolviendo una representación de texto plano donde cada nodo de nivel superior está separado por un solo \n carácter de nueva línea para una entrada de const nodes = \[ { type 'paragraph', children \[{ text 'an opening paragraph ' }], }, { type 'quote', children \[{ text 'a wise quote ' }], }, { type 'paragraph', children \[{ text 'a closing paragraph!' }], }, ] terminarías con an opening paragraph a wise quote a closing paragraph! nota cómo el bloque de cita no es distinguible de ninguna manera, eso es porque estamos hablando de texto sin formato pero puedes serializar los datos a cualquier cosa que desees—después de todo, es solo json html por ejemplo, aquí hay una serializar función para html import escapehtml from 'escape html' import { text } from 'slate' const serialize = node => { if (text istext(node)) { let string = escapehtml(node text) if (node bold) { string = `\<strong>${string}\</strong>` } return string } const children = node children map(n => serialize(n)) join('') switch (node type) { case 'quote' return `\<blockquote>\<p>${children}\</p>\</blockquote>` case 'paragraph' return `\<p>${children}\</p>` case 'link' return `\<a href="${escapehtml(node url)}">${children}\</a>` default return children } } este es un poco más consciente que el serializador de texto sin formato anterior en realidad es recursivo para que pueda seguir iterando más profundamente a través de los hijos de un nodo hasta que llegue a los nodos de texto hoja y para cada nodo que recibe, lo convierte en una cadena html también toma un solo nodo como entrada en lugar de un array, así que si pasas un editor como const editor = { children \[ { type 'paragraph', children \[ { text 'an opening paragraph with a ' }, { type 'link', url 'https //example com', children \[{ text 'link' }], }, { text ' in it ' }, ], }, { type 'quote', children \[{ text 'a wise quote ' }], }, { type 'paragraph', children \[{ text 'a closing paragraph!' }], }, ], // `editor` objects also have other properties that are omitted here } recibirías de vuelta (saltos de línea añadidos para legibilidad) \<p>an opening paragraph with a \<a href="https //example com">link\</a> in it \</p> \<blockquote>\<p>a wise quote \</p>\</blockquote> \<p>a closing paragraph!\</p> ¡es realmente así de fácil! deserializando otro caso de uso común en slate es hacer lo contrario deserializar esto es cuando tienes alguna entrada arbitraria y quieres convertirla en una estructura json compatible con slate por ejemplo, cuando alguien pega html en tu editor y quieres asegurarte de que se analice con el formato adecuado para tu editor slate tiene un ayudante incorporado para esto el slate hyperscript paquete la forma más común de usar slate hyperscript es para escribir documentos jsx, por ejemplo, al escribir pruebas podrías usarlo así / @jsx jsx / import { jsx } from 'slate hyperscript' const input = ( \<fragment> \<element type="paragraph">a line of text \</element> \</fragment> ) y la función jsx de tu compilador (babel, typescript, etc ) convertiría esa entrada variable en const input = \[ { type 'paragraph', children \[{ text 'a line of text ' }], }, ] esto es genial para casos de prueba, o lugares donde quieres poder escribir muchos objetos de slate en una forma muy legible ¡sin embargo! esto no ayuda con la deserialización pero slate hyperscript no es solo para jsx es solo una forma de construir árboles de contenido de slate lo cual resulta ser exactamente lo que quieres hacer cuando estás deserializando algo como html por ejemplo, aquí hay una función de deserialización para html import { jsx } from 'slate hyperscript' const deserialize = el => { if (el nodetype === 3) { return el textcontent } else if (el nodetype !== 1) { return null } let children = array from(el childnodes) map(deserialize) if (children length === 0) { children = \[{ text '' }] } switch (el nodename) { case 'body' return jsx('fragment', {}, children) case 'br' return '\n' case 'blockquote' return jsx('element', { type 'quote' }, children) case 'p' return jsx('element', { type 'paragraph' }, children) case 'a' return jsx( 'element', { type 'link', url el getattribute('href') }, children ) default return el textcontent } } toma un el objeto de elemento html y devuelve un fragmento de slate así que si tienes una cadena html, puedes analizar y deserializarla así const html = ' ' const document = new domparser() parsefromstring(html, 'text/html') deserialize(document body) con esta entrada \<p>an opening paragraph with a \<a href="https //example com">link\</a> in it \</p> \<blockquote>\<p>a wise quote \</p>\</blockquote> \<p>a closing paragraph!\</p> terminarías con esta salida const fragment = \[ { type 'paragraph', children \[ { text 'an opening paragraph with a ' }, { type 'link', url 'https //example com', children \[{ text 'link' }], }, { text ' in it ' }, ], }, { type 'quote', children \[ { type 'paragraph', children \[{ text 'a wise quote ' }], }, ], }, { type 'paragraph', children \[{ text 'a closing paragraph!' }], }, ] y al igual que la función de serialización, puedes extenderla para adaptarla a las necesidades exactas de tu modelo de dominio
