Construyendo un editor de código web

 

 

 

  • Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX
  • Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost

  • Índice
    1. Usando CodeMirror #
    2. Creando un nuevo proyecto de reacción #
      1. Componente de botón #
    3. Creando los editores #
      1. componentes Editor.jsx #
      2. Temas de CodeMirror #
      3. src App.js #
    4. Introducción a los marcos flotantes #
      1. Cómo funcionan los iframes en React #
      2. El futuro de los iframes en la Web #
    5. Creando el Iframe para albergar nuestro resultado #
      1. Configurar el Iframe para mostrar el resultado #

    Si es un desarrollador que está pensando en crear una plataforma que requiera un editor de código de una forma u otra, entonces este artículo es para usted. Este artículo explica cómo crear un editor de código web que muestre el resultado en tiempo real con la ayuda de HTML, CSS y JavaScript.

     

    Un editor de código web en línea es más útil cuando no tienes la oportunidad de utilizar una aplicación de edición de código o cuando quieres probar rápidamente algo en la web con tu computadora o incluso tu teléfono móvil. Este también es un proyecto interesante en el que trabajar porque tener el conocimiento de cómo construir un editor de código le dará ideas sobre cómo abordar otros proyectos que requieren que integre un editor de código para mostrar alguna funcionalidad.

    Aquí hay algunos conceptos de React que necesitará saber para poder seguir este artículo:

    • Manos,
    • estructura de componentes,
    • Componentes funcionales,
    • Accesorios.

    Usando CodeMirror #

    Usaremos una biblioteca llamada CodeMirror para construir nuestro editor. CodeMirror es un editor de texto versátil implementado en JavaScript para el navegador. Es especialmente para editar código y viene con varios modos de idioma y complementos para una funcionalidad de edición más avanzada.

     

    Se encuentran disponibles una rica API de programación y un sistema de temas CSS para personalizar CodeMirror para adaptarlo a su aplicación y ampliarla con nuevas funciones. Nos brinda la funcionalidad de crear un editor de código enriquecido que se ejecuta en la web y nos muestra el resultado de nuestro código en tiempo real.

    En la siguiente sección, configuraremos nuestro nuevo proyecto React e instalaremos las bibliotecas que necesitamos para crear nuestra aplicación web.

    Creando un nuevo proyecto de reacción #

    Comencemos creando un nuevo proyecto de React. En su interfaz de línea de comandos, navegue hasta el directorio en el que desea crear su proyecto, creemos una aplicación React y le ponemos un nombre code_editor:

    npx create-react-app code_editor

    Habiendo creado nuestra nueva aplicación React, naveguemos hasta el directorio de ese proyecto en la interfaz de línea de comandos:

    cd code_editor

    Hay dos bibliotecas que necesitamos instalar aquí: codemirrory react-codemirror2.

    npm install codemirror react-codemirror2

    Una vez instaladas las bibliotecas que necesitamos para este proyecto, creemos nuestras pestañas y habilitemos el cambio de pestañas entre las tres pestañas que aparecerán en nuestro editor (para HTML, CSS y JavaScript).

    Componente de botón #

    En lugar de crear botones individuales, hagamos del botón un componente reutilizable. En nuestro proyecto, el botón tendría tres instancias, según las tres pestañas que necesitemos.

    Cree una carpeta nombrada componentsen la srccarpeta. En esta nueva componentscarpeta, cree un archivo JSX llamado Button.jsx.

    Aquí está todo el código necesario en el Buttoncomponente:

    import React from 'react'const Button = ({title, onClick}) = { return ( div button style={{ maxWidth: "140px", minWidth: "80px", height: "30px", marginRight: "5px" }} onClick={onClick} {title} /button /div )}export default Button

    Aquí hay una explicación completa de lo que hicimos arriba:

    • Creamos un componente funcional llamado Button, que luego exportamos.
    • Desestructuramos titley onClickde los accesorios que entran en el componente. Aquí, titlesería una cadena de texto y onClicksería una función que se llama cuando se hace clic en un botón.
    • A continuación, usamos el buttonelemento para declarar nuestro botón y usamos los styleatributos para darle estilo a nuestro botón para que se vea presentable.
    • Agregamos el onClickatributo y onClickle pasamos nuestros accesorios de función desestructurados.
    • Lo último que notará que hicimos en este componente es pasar {title}el contenido de la buttonetiqueta. Esto nos permite mostrar el título dinámicamente, según el accesorio que se pasa a la instancia del componente del botón cuando se llama.

    Ahora que hemos creado un componente de botón reutilizable, avancemos y llevemos nuestro componente a App.js.Ir a App.jse importemos el componente de botón recién creado:

     

    import Button from './components/Button';

    Para rastrear qué pestaña o editor está abierto, necesitamos un estado de declaración para contener el valor del editor que está abierto. Usando el useStategancho React, configuraremos el estado que almacenará el nombre de la pestaña del editor que está actualmente abierta cuando se hace clic en el botón de esa pestaña.

    Así es como lo hacemos:

    import React, { useState } from 'react';import './App.css';import Button from './components/Button';function App() { const [openedEditor, setOpenedEditor] = useState('html'); return ( div className="App" /div );}export default App;

    Aquí declaramos nuestro estado. Toma el nombre del editor que está abierto actualmente. Debido a que el valor htmlse pasa como valor predeterminado del estado, el editor HTML sería la pestaña abierta de forma predeterminada.

    Sigamos adelante y escribamos la función que se utilizará setOpenedEditorpara cambiar el valor del estado cuando se haga clic en un botón de pestaña.

    Nota: Es posible que no estén abiertas dos pestañas al mismo tiempo, por lo que tendremos que tenerlo en cuenta al escribir nuestra función.

    Así es como onTabClickse ve nuestra función, llamada ,:

    import React, { useState } from 'react';import './App.css';import Button from './components/Button';function App() { ... const onTabClick = (editorName) = { setOpenedEditor(editorName); }; return ( div className="App" /div );}export default App;

    Aquí, pasamos un único argumento de función, que es el nombre de la pestaña actualmente seleccionada. Este argumento se proporcionaría en cualquier lugar donde se llame a la función y se pasaría el nombre relevante de esa pestaña.

    Creemos tres instancias de nuestro Buttonpara las tres pestañas que necesitamos:

    div className="App" pWelcome to the editor!/p div className="tab-button-container" Button onClick={() = { onTabClick('html') }} / Button onClick={() = { onTabClick('css') }} / Button onClick={() = { onTabClick('js') }} / /div /div

    Aquí está lo que hicimos:

    • Comenzamos agregando una petiqueta, básicamente para dar algo de contexto sobre de qué se trata nuestra aplicación.
    • Usamos una divetiqueta para envolver nuestros botones de pestaña. La divetiqueta lleva un classNameque usaremos para diseñar los botones en una visualización de cuadrícula en el archivo CSS más adelante en este tutorial.
    • A continuación, declaramos tres instancias del Buttoncomponente. Si recuerdas, el Buttoncomponente requiere dos accesorios titley onClick. En cada instancia del Buttoncomponente, se proporcionan estos dos accesorios.
    • El titleaccesorio toma el título de la pestaña.
    • El onClickaccesorio toma una función, onTabClickque acabamos de crear y que toma un solo argumento: el nombre de la pestaña seleccionada.

    Según la pestaña seleccionada actualmente, usaríamos el operador ternario de JavaScript para mostrar la pestaña de forma condicional. Esto significa que si el valor del openedEditorestado se establece en html(es decir setOpenedEditor('html')), la pestaña de la sección HTML se convertirá en la pestaña actualmente visible. Comprenderá esto mejor mientras lo hacemos a continuación:

     

    ...return ( div className="App" ... div className="editor-container" { openedEditor === 'html' ? ( pThe html editor is open/p ) : openedEditor === 'css' ? ( pThe CSS editor is open!!!!!!/p ) : ( pthe JavaScript editor is open/p ) } /div /div );...

    Repasemos el código anterior en inglés sencillo. Si el valor de openedEditores html, muestre la sección HTML. De lo contrario, si el valor de openedEditores css, muestre la sección CSS. De lo contrario, si el valor no es htmlni ni css, entonces eso significa que el valor debe ser js, porque sólo tenemos tres valores posibles para el openedEditorestado; entonces mostraríamos la pestaña de JavaScript.

    Usamos etiquetas de párrafo ( p) para las diferentes secciones en las condiciones del operador ternario. A medida que avancemos, crearemos los componentes del editor y reemplazaremos las petiquetas con los propios componentes del editor.

    ¡Ya hemos llegado tan lejos! Cuando se hace clic en un botón, se activa la acción que establece la pestaña que representa true, haciendo que esa pestaña sea visible. Así es como se ve nuestra aplicación actualmente:

    Agreguemos un poco de CSS al divcontenedor que contiene los botones. Queremos que los botones se muestren en una cuadrícula, en lugar de apilarse verticalmente como en la imagen de arriba. Vaya a su App.cssarchivo y agregue el siguiente código:

    .tab-button-container{ display: flex;}

    Recuerde que agregamos className="tab-button-container"como atributo en la divetiqueta que contiene los botones de tres pestañas. Aquí, le dimos estilo a ese contenedor, usando CSS para configurar su visualización en flex. Este es el resultado:

    Siéntete orgulloso de lo mucho que has hecho para llegar a este punto. En la siguiente sección, crearemos nuestros editores, reemplazando las petiquetas con ellos.

     

    Creando los editores #

    Como ya hemos instalado las bibliotecas en las que vamos a trabajar en nuestro editor CodeMirror, sigamos adelante y creemos nuestro Editor.jsxarchivo en la componentscarpeta.

    componentes Editor.jsx #

    Habiendo creado nuestro nuevo archivo, escribamos un código inicial en él:

    import React, { useState } from 'react';import 'codemirror/lib/codemirror.css';import { Controlled as ControlledEditorComponent } from 'react-codemirror2';const Editor = ({ language, value, setEditorState }) = { return ( div className="editor-container" /div )}export default Editor

    Esto es lo que hicimos:

    • Importamos React junto con el useStategancho porque lo vamos a necesitar.
    • Importamos el archivo CSS CodeMirror (que proviene de la biblioteca CodeMirror que instalamos, por lo que no es necesario instalarlo de ninguna manera especial).
    • Importamos Controlleddesde react-codemirror2, renombrándolo para ControlledEditorComponentque quede más claro. Usaremos esto en breve.
    • Luego, declaramos nuestro Editorcomponente funcional y tenemos una declaración de devolución con un vacío div, con un classNameen la declaración de devolución por ahora.

    En nuestro componente funcional, desestructuramos algunos valores de los accesorios, incluidos language, valuey setEditorState. Estos tres accesorios se proporcionarían en cualquier instancia del editor cuando se llame App.js.

    Usemos ControlledEditorComponentpara escribir el código para nuestro editor. Esto es lo que haremos:

    import React, { useState } from 'react';import 'codemirror/lib/codemirror.css';import 'codemirror/mode/xml/xml';import 'codemirror/mode/javascript/javascript';import 'codemirror/mode/css/css';import { Controlled as ControlledEditorComponent } from 'react-codemirror2';const Editor = ({ language, value, setEditorState }) = { return ( div className="editor-container" ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, }} / /div )}export default Editor

    Repasemos lo que hicimos aquí, explicando algunos términos de CodeMirror.

    Los modos CodeMirror especifican para qué idioma está diseñado un editor. Importamos tres modos porque tenemos tres editores para este proyecto:

    1. XML: este modo es para HTML. Utiliza el término XML.
    2. JavaScript: Esto ( codemirror/mode/javascript/javascript) trae el modo JavaScript.
    3. CSS: Esto ( codemirror/mode/css/css) trae el modo CSS.

    Nota: Debido a que el editor está construido como un componente reutilizable, no podemos poner un modo directo en el editor. Entonces, suministramos el modo a través del languageaccesorio que desestructuramos. Pero esto no cambia el hecho de que los modos deben importarse para que funcionen. Juegos gratis

    A continuación, analicemos las cosas en ControlledEditorComponent:

     

    • onBeforeChange
      Esto se llama cada vez que escribe o elimina del editor. Piense en esto como el onChangecontrolador que normalmente tendría en un campo de entrada para realizar un seguimiento de los cambios. Al usar esto, podremos obtener el valor de nuestro editor cada vez que haya un nuevo cambio y guardarlo en el estado de nuestro editor. Escribiremos la {handleChange}función a medida que avancemos.
    • value = {value}
      Este es solo el contenido del editor en un momento dado. Pasamos un accesorio desestructurado llamado valueeste atributo. Los valueaccesorios son el estado que posee el valor de ese editor. Esto se proporcionaría desde la instancia del editor.
    • className="code-mirror-wrapper"
      El nombre de esta clase no es un estilo que creamos nosotros mismos. Se suministra desde el archivo CSS de CodeMirror, que importamos anteriormente.
    • options
      Este es un objeto que toma las diferentes funcionalidades que queremos que tenga nuestro editor. Hay muchas opciones sorprendentes en CodeMirror. Veamos los que usamos aquí:
      • lineWrapping: true
        Esto significa que el código debe pasar a la siguiente línea cuando la línea esté llena.
      • lint: true
        Esto permite que se formen pelusas.
      • mode: language
        Este modo, como se mencionó anteriormente, toma el idioma para el que se utilizará el editor. El idioma ya se importó anteriormente, pero el editor aplicará un idioma basado en el languagevalor proporcionado al editor a través del accesorio.
      • lineNumbers: true
        Esto especifica que el editor debe tener números de línea para cada línea.

    A continuación, podemos escribir la handleChangefunción para el onBeforeChangecontrolador:

    const handleChange = (editor, data, value) = { setEditorState(value);}

    El onBeforeChangecontrolador nos da acceso a tres cosas: editor, data, value.

    Solo necesitamos valueporque es lo que queremos pasar en nuestro setEditorStateaccesorio. La setEditorStatepropiedad representa el valor establecido para cada estado que declaramos en App.js, manteniendo el valor para cada editor. A medida que avancemos, veremos cómo pasar esto como accesorio al Editorcomponente.

    A continuación, agregaremos un menú desplegable que nos permitirá seleccionar diferentes temas para el editor. Entonces, veamos los temas en CodeMirror.

    Temas de CodeMirror #

    CodeMirror tiene varios temas entre los que podemos seleccionar. Visite el sitio web oficial para ver demostraciones de los diferentes temas disponibles. Hagamos un desplegable con diferentes temas que el usuario puede elegir en nuestro editor. Para este tutorial, agregaremos cinco temas, pero puedes agregar tantos como quieras.

    Primero, importemos nuestros temas en el Editor.jscomponente:

    import 'codemirror/theme/dracula.css';import 'codemirror/theme/material.css';import 'codemirror/theme/mdn-like.css';import 'codemirror/theme/the-matrix.css';import 'codemirror/theme/night.css';

    A continuación, cree una matriz de todos los temas que hemos importado:

     

    const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']

    Declaremos un useStategancho para contener el valor del tema seleccionado y establezcamos el tema predeterminado como dracula:

    const [theme, setTheme] = useState("dracula")

    Creemos el menú desplegable:

    ...return ( div className="editor-container" div style={{marginBottom: "10px"}} label for="cars"Choose a theme: /label select name="theme" onChange={(el) = { setTheme(el.target.value) }} { themeArray.map( theme = ( option value={theme}{theme}/option )) } /select /div // the rest of the code comes below... /div )...

    En el código anterior, usamos la labeletiqueta HTML para agregar una etiqueta a nuestro menú desplegable y luego agregamos la selectetiqueta HTML para crear nuestro menú desplegable. La optionetiqueta en el selectelemento define las opciones disponibles en el menú desplegable.

    Debido a que necesitábamos llenar el menú desplegable con los nombres de los temas themeArrayque creamos, usamos el .mapmétodo de matriz para mapear themeArrayy mostrar los nombres individualmente usando la optionetiqueta.

    Espera, aún no hemos terminado de explicar el código anterior. En la selectetiqueta de apertura, pasamos el onChangeatributo para rastrear y actualizar el themeestado cada vez que se selecciona un nuevo valor en el menú desplegable. Cada vez que se selecciona una nueva opción en el menú desplegable, el valor se obtiene del objeto que se nos devuelve. A continuación, utilizamos el setThemeenlace de nuestro estado para establecer que el nuevo valor sea el valor que contiene el estado.

    En este punto, hemos creado nuestro menú desplegable, configuramos el estado de nuestro tema y escribimos nuestra función para establecer el estado con el nuevo valor. Lo último que debemos hacer para que CodeMirror use nuestro tema es pasar el tema al optionsobjeto en ControlledEditorComponent. En el optionsobjeto, agreguemos un valor llamado themey establezcamos su valor en el valor del estado para el tema seleccionado, también llamado theme.

    Así es como ControlledEditorComponentse vería ahora:

    ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }}/

    Ahora, hemos creado un menú desplegable de diferentes temas que se pueden seleccionar en el editor.

    Así es como Editor.jsse ve el código completo en este momento:

    import React, { useState } from 'react';import 'codemirror/lib/codemirror.css';import 'codemirror/theme/dracula.css';import 'codemirror/theme/material.css';import 'codemirror/theme/mdn-like.css';import 'codemirror/theme/the-matrix.css';import 'codemirror/theme/night.css';import 'codemirror/mode/xml/xml';import 'codemirror/mode/javascript/javascript';import 'codemirror/mode/css/css';import { Controlled as ControlledEditorComponent } from 'react-codemirror2';const Editor = ({ language, value, setEditorState }) = { const [theme, setTheme] = useState("dracula") const handleChange = (editor, data, value) = { setEditorState(value); } const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night'] return ( div className="editor-container" div style={{marginBottom: "10px"}} label for="themes"Choose a theme: /label select name="theme" onChange={(el) = { setTheme(el.target.value) }} { themeArray.map( theme = ( option value={theme}{theme}/option )) } /select /div ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} / /div )}export default Editor

    Sólo hay uno classNameque necesitamos diseñar. Vaya App.cssy agregue el siguiente estilo:

     

    .editor-container{ padding-top: 0.4%;}

    Ahora que nuestros editores están listos, regresemos App.jsy usémoslos allí.

    src App.js #

    Lo primero que debemos hacer es importar el Editor.jscomponente aquí:

    import Editor from './components/Editor';

    En App.js, declaremos los estados que contendrán el contenido de los editores HTML, CSS y JavaScript, respectivamente.

    const [html, setHtml] = useState('');const [css, setCss] = useState('');const [js, setJs] = useState('');

    Si recuerda, necesitaremos utilizar estos estados para conservar y suministrar los contenidos de nuestros editores.

    A continuación, reemplacemos las petiquetas de párrafo ( ) que usamos para HTML, CSS y JavaScript en las representaciones condicionales con los componentes del editor que acabamos de crear, y también pasaremos el accesorio apropiado a cada instancia del componente del editor. :

    function App() { ... return ( div className="App" pWelcome to the edior/p // This is where the tab buttons container is... div className="editor-container" { htmlEditorIsOpen ? ( Editor language="xml" value={html} setEditorState={setHtml} / ) : cssEditorIsOpen ? ( Editor language="css" value={css} setEditorState={setCss} / ) : ( Editor language="javascript" value={js} setEditorState={setJs} / ) } /div /div );}export default App;

    Si ha estado siguiendo hasta ahora, comprenderá lo que hicimos en el bloque de código anterior.

    Aquí está en inglés sencillo: reemplazamos las petiquetas (que estaban allí como marcadores de posición) con instancias de los componentes del editor. Luego, proporcionamos sus accesorios language, valuey setEditorState, respectivamente, para que coincidan con sus estados correspondientes.

     

    ¡Hemos llegado tan lejos! Así es como se ve nuestra aplicación ahora:

    Introducción a los marcos flotantes #

    Usaremos marcos en línea (iframes) para mostrar el resultado del código ingresado en el editor.

    Según MDN :

    El elemento HTML Inline Frame ( iframe) representa un contexto de navegación anidado , incrustando otra página HTML en la actual.

    Cómo funcionan los iframes en React #

    Los iframes se utilizan normalmente con HTML simple. El uso de Iframes con React no requiere muchos cambios, el principal es convertir los nombres de los atributos a camelcase. Un ejemplo de esto es lo que srcdocse convertiría en srcDoc.

    El futuro de los iframes en la Web #

    Los iframes siguen siendo realmente útiles en el desarrollo web. Algo que quizás quieras consultar son los Portales. Como explica Daniel Brain :

    “Los portales introducen un nuevo y poderoso conjunto de capacidades en esta combinación. Ahora es posible crear algo que parezca un iframe, que pueda animarse y transformarse sin problemas y ocupar toda la ventana del navegador”.

    Una de las cosas que Portals intenta solucionar es el problema de la barra de URL. Cuando se utiliza iframe, los componentes representados en el iframe no llevan una URL única en la barra de direcciones; como tal, es posible que esto no sea excelente para la experiencia del usuario, según el caso de uso. Vale la pena echarle un vistazo a Portals, y te sugiero que lo hagas, pero como no es el tema central de nuestro artículo, esto es todo lo que diré al respecto aquí.

    Creando el Iframe para albergar nuestro resultado #

    Sigamos adelante con nuestro tutorial creando un iframe para albergar el resultado de nuestros editores.

    return ( div className="App" // ... div iframe srcDoc={srcDoc} sandbox="allow-scripts" frameBorder="1" / /div /div );

    Aquí, creamos el iframe y lo alojamos en una divetiqueta de contenedor. En el iframe, pasamos algunos atributos que necesitamos:

    • srcDoc
      El srcDocatributo está escrito en camelcase porque así es como se escriben atributos de iframe en React. Cuando utilizamos un iframe, podemos incrustar una página web externa en la página o representar contenido HTML específico. Para cargar e incrustar una página externa, usaríamos la srcpropiedad en su lugar. En nuestro caso, no estamos cargando una página externa; más bien, queremos crear un nuevo documento HTML interno que contenga nuestro resultado; para esto necesitamos el srcDocatributo. Este atributo toma el documento HTML que queremos incrustar (aún no lo hemos creado, pero lo haremos pronto).
    • title
      El atributo de título se utiliza para describir el contenido del marco en línea.
    • sandbox
      Esta propiedad tiene muchos propósitos . En nuestro caso, lo estamos usando para permitir que se ejecuten scripts en nuestro iframe con el allow-scriptsvalor. Debido a que estamos trabajando con un editor de JavaScript, esto resultaría útil rápidamente.
    • frameBorder
      Esto simplemente define el grosor del borde del iframe.
    • widthy height
      Esto define el ancho y alto del iframe.

    Estos términos ahora deberían tener más sentido para usted. Sigamos adelante y declaremos el estado que contendrá el documento de plantilla HTML para srcDoc. Si observa detenidamente el bloque de código anterior, verá que le pasamos un valor al srcDocatributo: . Usemos nuestro gancho React para declarar el estado. Para hacer esto, en el archivo, vaya a donde definimos los otros estados y agregue este:srcDoc={srcDoc}useState()srcDocApp.js

    const [srcDoc, setSrcDoc] = useState(` `);

    Ahora que hemos creado el estado, lo siguiente que debemos hacer es mostrar el resultado en el estado cada vez que escribamos en el editor de código. Pero lo que no queremos es volver a renderizar el componente cada vez que presionamos una tecla. Con eso en mente, procedamos.

    Configurar el Iframe para mostrar el resultado #

    Cada vez que hay un cambio en cualquiera de los editores de HTML, CSS y JavaScript, respectivamente, queremos useEffect()que se active y eso mostrará el resultado actualizado en el iframe. Escribamos useEffect()para hacer esto en el App.jsarchivo:

    Primero, importe el useEffect()gancho:

    import React, { useState, useEffect } from 'react';

    Escribamos useEffect()así:

    useEffect(() = { const timeOut = setTimeout(() = { setSrcDoc( ` html body${html}/body style${css}/style script${js}/script /html ` ) }, 250); return () = clearTimeout(timeOut) }, [html, css, js])

    Aquí, escribimos un useEffect()enlace que siempre se ejecutará cada vez que se cambien o actualicen los estados de v






    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Construyendo un editor de código web

    Construyendo un editor de código web

    Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost Índi

    programar

    es

    https://aprendeprogramando.es/static/images/programar-construyendo-un-editor-de-codigo-web-1128-0.jpg

    2024-04-04

     

    Construyendo un editor de código web
    Construyendo un editor de código web

     

     

    Top 20