diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:41:45 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:41:45 -0500 |
commit | 1109132f09d75da9a28b649c7677bb6ce07c40c0 (patch) | |
tree | 0dd8b084480983cf9f9680e8aedb92782a921b13 /files/es/web/web_components | |
parent | 4b1a9203c547c019fc5398082ae19a3f3d4c3efe (diff) | |
download | translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.tar.gz translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.tar.bz2 translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.zip |
initial commit
Diffstat (limited to 'files/es/web/web_components')
-rw-r--r-- | files/es/web/web_components/custom_elements/index.html | 181 | ||||
-rw-r--r-- | files/es/web/web_components/index.html | 224 | ||||
-rw-r--r-- | files/es/web/web_components/using_custom_elements/index.html | 304 | ||||
-rw-r--r-- | files/es/web/web_components/using_shadow_dom/index.html | 199 | ||||
-rw-r--r-- | files/es/web/web_components/using_templates_and_slots/index.html | 335 |
5 files changed, 1243 insertions, 0 deletions
diff --git a/files/es/web/web_components/custom_elements/index.html b/files/es/web/web_components/custom_elements/index.html new file mode 100644 index 0000000000..4a789f98d2 --- /dev/null +++ b/files/es/web/web_components/custom_elements/index.html @@ -0,0 +1,181 @@ +--- +title: Custom Elements +slug: Web/Web_Components/Custom_Elements +tags: + - Componentes Web + - Web Components + - custom elements +translation_of: Web/Web_Components/Using_custom_elements +--- +<p>Los <em>Custom Elements </em>son una característica que permite crear tus propios <a href="https://developer.mozilla.org/en-US/docs/Glossary/Element">elementos</a> HTML personalizados. Pueden tener un comportamiento personalizado y estilos CSS propios. Son una parte de los <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components">Web Components</a>, pero también pueden ser utilizados independientemente.</p> + +<div class="note"> +<p><strong>Nota:</strong> Los <em>Custom elements</em> sólo se han estabilizado recientemente, y partes de MDN todavía contienen información desactualizada de las APIs de los antiguos borradores de la especificación.</p> +</div> + +<p>Puede no estar claro por qué se creó la nueva capacidad de elementos personalizados, ya que ya era posible crear una etiqueta como <code><mytag></code> y aplicarle estilo con CSS, luego utilizar scripts para darle comportamiento. Una ventaja que tienen los <em>custom elements</em> son las reacciones de ciclo de vida (<em>lifecycle reactions)</em>, que permiten asociar comportamiento a diferentes partes del nuevo "ciclo de vida" del elemento. Por ejemplo, se puede asociar un comportamiento concreto cuando un nuevo elemento se inserta en el DOM ("conectado"), y otro distinto cuando es eliminado del DOM ("desconectado"), o cuando sus atributos cambien.</p> + +<p>El habilitador de claves de los elementos personalizados v1 es el método {{domxref("CustomElementRegistry.define()")}}, el cual se puede utilizar para definir un nuevo elemento personalizado. El nuevo elemento utilizará la clase suministrada para cualquier instancia, en lugar del valor predeterminado {{domxref("HTMLUnknownElement")}}. Los elementos personalizados pueden basarse en un elemento nativo como <code><button></code>, utilizando la sintaxis <code><button is="my-button"></code>; estos se llaman <em>elementos integrados personalizados.</em></p> + +<h2 id="Métodos_de_custom_element">Métodos de <em>custom element</em></h2> + +<p>Los <em>Custom elements</em> tienen los siguientes métodos que dictan su comportamiento:</p> + +<dl> + <dt>constructor()</dt> + <dd>Llamado cuando el elemento es creado o actualizado</dd> + <dt>connectedCallback()</dt> + <dd>Llamado cuando el elemento se es insertado en el documento, incluyéndose en un árbol shadow</dd> + <dt>disconnectedCallback()</dt> + <dd>Llamado cuando el elemento es eliminado de un documento</dd> + <dt>attributeChangedCallback(nombreDelAtributo, antiguoValor, nuevoValor, dominio)</dt> + <dd>Llamado cuando un atributo es cambiado, concatenado, eliminado o reemplazado en el elemento. Sólo llamado sobre <a href="#Atributos_Observados">atributos observados</a>.</dd> + <dt>adoptedCallback(antiguoDocumento, nuevoDocumento)</dt> + <dd>Llamado cuando un elemento es adoptado en otro nuevo documento</dd> +</dl> + +<h2 id="Ejemplo">Ejemplo</h2> + +<p>Los <em>custom elements</em> necesitan usar la <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes">sintaxis de clase</a> introducida en las versiones modernas de JavaScript.</p> + +<p>Archivo HTML:</p> + +<pre class="brush: html">Si no aparece nada debajo, es que tu navegador no soporta aún los Custom Elements. +<x-product data-name="Ruby" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/ruby.png" data-url="http://example.com/1"></x-product> +<x-product data-name="JavaScript" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/javascript.png" data-url="http://example.com/2"></x-product> +<x-product data-name="Python" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/python.png" data-url="http://example.com/3"></x-product></pre> + +<p>Archivo JS:</p> + +<pre class="brush: js">// Declaración de un <em>custom element</em> que hereda de HTMLElement +class XProduct extends HTMLElement { + constructor() { + // Siempre debe llamarse primero al constructor padre + super(); + + // Se crea el <em>shadow root</em> + var shadow = this.attachShadow({mode: 'open'}); + + // Se crea un elemnto img y se asignan sus atributos. + var img = document.createElement('img'); + img.alt = this.getAttribute('data-name'); + img.src = this.getAttribute('data-img'); + img.width = '150'; + img.height = '150'; + img.className = 'product-img'; + + // Añadir la imagen al shadow root. + shadow.appendChild(img); + + // Añadir un elemento de escucha a la imagen. + img.addEventListener('click', () => { + window.location = this.getAttribute('data-url'); + }); + + // Crear un enlace al producto. + var link = document.createElement('a'); + link.innerText = this.getAttribute('data-name'); + link.href = this.getAttribute('data-url'); + link.className = 'product-name'; + + // Añadir el enlace al shadow root. + shadow.appendChild(link); + } +} + +// Definir el nuevo elemento. +customElements.define('x-product', XProduct); +</pre> + +<p>Archivo CSS:</p> + +<pre class="brush: css">body { + background: #F7F7F7; +} + +x-product { + display: inline-block; + float: left; + margin: 0.5em; + border-radius: 3px; + background: #FFF; + box-shadow: 0 1px 3px rgba(0,0,0,0.25); + font-family: Helvetica, arial, sans-serif; + -webkit-font-smoothing: antialiased; +} + +x-product::slotted(.product-img) { + cursor: pointer; + background: #FFF; + margin: 0.5em; +} + +x-product::slotted(.product-name) { + display: block; + text-align: center; + text-decoration: none; + color: #08C; + border-top: 1px solid #EEE; + font-weight: bold; + padding: 0.75em 0; +} +</pre> + +<p>A continuación se muestra el ejemplo en vivo de lo anterior:</p> + +<p>{{ EmbedLiveSample('Example', '1500', '250', '', 'Web/Web_Components/Custom_Elements') }}</p> + +<h2 id="Atributos_Observados">Atributos Observados</h2> + +<p>Para ser notificado cuando un atributo cambia, se debe definir una lista de atributos observados al inicializar el elemento, poniendo un getter estático <code>observedAttributes</code> en la clase del elemento que devuelve un array de nombre de atributos.</p> + +<p>Archivo JS:</p> + +<pre class="brush: js">class HelloElement extends HTMLElement { + // Observar los cambios en el atributo 'name'. + static get observedAttributes() {return ['name']; } + + // Responder a los cambios en el atributo. + attributeChangedCallback(attr, oldValue, newValue) { + if (attr == 'name') { + this.textContent = `Hello, ${newValue}`; + } + } +} + +// Definir el nuevo elemento +customElements.define('hello-element', HelloElement); +</pre> + +<p>Archivo HTML:</p> + +<pre class="brush: html"><hello-element name="Anita"></hello-element></pre> + +<p>A continuación está el ejemplo en vivo de lo anterior:</p> + +<p>{{ EmbedLiveSample('Observed_attributes', '750', '100', '', 'Web/Web_Components/Custom_Elements') }}</p> + +<h2 id="Especificaciones">Especificaciones</h2> + +<p>Los <em>Custom Elements </em>están definido en la siguiente especificación:</p> + +<table class="spec-table standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + <th scope="col">Estado</th> + <th scope="col">Comentario</th> + </tr> + <tr> + <td><a href="https://html.spec.whatwg.org/multipage/scripting.html#custom-elements">The HTML Standard: Custom elements</a></td> + <td>LS</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="Recursos">Recursos</h2> + +<ul> + <li><a href="https://developers.google.com/web/fundamentals/primers/customelements/">Custom elements v1: reusable web components - Google Developers tutorial</a></li> +</ul> diff --git a/files/es/web/web_components/index.html b/files/es/web/web_components/index.html new file mode 100644 index 0000000000..96e3250cb2 --- /dev/null +++ b/files/es/web/web_components/index.html @@ -0,0 +1,224 @@ +--- +title: Web Components +slug: Web/Web_Components +tags: + - Componentes + - Componentes Web + - Landing + - TopicStub + - Web Components +translation_of: Web/Web_Components +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<div class="summary"> +<p>Los Componentes Web son un paquete de diferentes tecnologías que te permiten crear elementos personalizados reutilizables — con su funcionalidad encapsulada apartada del resto del código — y utilizarlos en las aplicaciones web.</p> +</div> + +<h2 id="Conceptos_y_uso">Conceptos y uso</h2> + +<p>Como desarrolladores, sabemos que reutilizar código tanto como sea posible es una buena idea. Esto tradicionalmente no es sencillo para estructuras de marcado personalizadas — piense en el complejo HTML (y sus estilos y scripts asociados) que en ocasiones se han tenido que escribir para renderizar controles de interfaz (UI) personalizados, y ahora usarlos múltiples veces puede crear un caos en la página si no se es cuidadoso.</p> + +<p>Los Componentes Web apuntan a resolver dichos problemas — consiste en tres tecnologías principalmente, las que se pueden usar juntas para crear elementos personalizables versátiles que encapsulan la funcionalidad y pueda ser reutilizada donde sea sin miedo a colisiones de código.</p> + +<ul> + <li><strong>Custom elements</strong> (elementos personalizados): Un conjunto de APIs de JavaScript que permiten definir elementos personalizados y su comportamiento, que entonces puede ser utilizado como se deseé en la interfaz del usuario.</li> + <li><strong>Shadow DOM</strong>: Un conjunto de APIs de JavaScript para fijar un árbol DOM "sombra" encapsulado a un elemento — que es renderizado por separado del documento DOM principal — y controlando funcionalidad asociada. De esta forma, se pueden mantener características de un elemento en privado, así puede tener el estilo y los scripts sin miedo de colisiones con otras partes del documento.</li> + <li><strong>HTML templates</strong> (plantillas HTML): Los elementos {{HTMLElement("template")}} y {{HTMLElement("slot")}} permiten escribir plantillas de marcado que no son desplegadas en la página renderizada. Éstas pueden ser reutilizadas en múltiples ocasiones como base de la estructura de un elemento personalizado.</li> +</ul> + +<p>La aproximación básica para implementar un componente web, generalmente es la siguiente:</p> + +<ol> + <li>Crear una clase o función en la cual especificar la funcionalidad del componente web. Si se usa una clase, usar la sintaxis de ES2015 (ver <a href="/en-US/docs/Web/JavaScript/Reference/Classes">Clases</a> para más información).</li> + <li>Registrar el nuevo elemento personalizado utilizando el método {{domxref("CustomElementRegistry.define()")}}, pasándole el nombre del elemento a ser definido, la clase o función en la cuál su funcionalidad esta especificada, y opcionalmente, de que elemento hereda.</li> + <li>Si se requiere, adjuntar un shadow DOM al elemento personalizado usando el método {{domxref("Element.attachShadow()")}}. Añadir elementos hijos, oyentes de eventos, etc., al shadow DOM utilizando métodos normales del DOM.</li> + <li>Si se requiere, definir una plantilla HTML utilizando {{htmlelement("template")}} y {{htmlelement("slot")}}. Nuevamente usar métodos regulares del DOM para clonar la plantilla y acoplarla al shadow DOM.</li> + <li>Utilizar los componentes personalizados en la página web cuando se desee, como se utilizaría cualquier otro elemento HTML.</li> +</ol> + +<h2 id="Tutoriales">Tutoriales</h2> + +<dl> + <dt><a href="/es/docs/Web/Web_Components/Using_custom_elements">Utilizando elementos personalizados (Using custom elements)</a></dt> + <dd>Guía que muestra como usar las características de los elementos personalizados para crear componentes web sencillos, así como revisar las llamadas del ciclo de vida y algunas características más avanzadas.</dd> + <dt><a href="/es/docs/Web/Web_Components/Using_shadow_DOM">Utilizando el shadow DOM</a></dt> + <dd>Guía que trata los fundamentos del shadow DOM, mostrando como adjuntar un shadow DOM a un elemento, añadir el árbol del shadow DOM, añadirle estilos y más.</dd> + <dt><a href="/es/docs/Web/Web_Components/Using_templates_and_slots">Usando templates y slots</a></dt> + <dd>Guía que muestra como definir una estructura HTML reutilizable utilizando elementos {{htmlelement("template")}} y {{htmlelement("slot")}} elements, y entonces usar esa estructura debto del componente web.</dd> +</dl> + +<h2 id="Referencia">Referencia</h2> + +<h3 id="Elementos_personalizados">Elementos personalizados</h3> + +<dl> + <dt>{{domxref("CustomElementRegistry")}}</dt> + <dd>Contiene funcionalidad relacionada a los elementos personalizados, más notablemente el método {{domxref("CustomElementRegistry.define()")}} utilizado para registrar nuevos elementos personalizados para que se puedan usar en el documento</dd> + <dt>{{domxref("Window.customElements")}}</dt> + <dd>Retorna una referencia al objeto <code>CustomElementRegistry</code>.</dd> + <dt><a href="/en-US/docs/Web/Web_Components/Using_custom_elements#Using_the_lifecycle_callbacks">Llamadas del ciclo de vida (Life cycle callbacks)</a></dt> + <dd>Llamadas de funciones especiales declaradas dentro de la clase de definición de los componentes personalizados, los que afectan su comportamiento: + <ul> + <li><code>connectedCallback</code>: Invocado cuando el componente personalizado se conecta por primera vez al DOM del documento.</li> + <li><code>disconnectedCallback</code>: Invocado cuando el componente personalizado se deconecta del DOM del documento.</li> + <li><code>adoptedCallback</code>: Invocado cuando el componente personalizado se mueve a un nuevo documento.</li> + <li><code>attributeChangedCallback</code>: Invocado cuando uno de los atributos del componente personalizado es añadido, removido o modificado.</li> + </ul> + </dd> + <dd> + <ul> + </ul> + </dd> +</dl> + +<dl> + <dt>Extensiones para crear elementos incorporados personalizados</dt> + <dd> + <ul> + <li>El atributo global HTML {{htmlattrxref("is")}}: Permite especificar que un elemento estandar HTML debe comportarse como un elemento incorporado personalizado registrado.</li> + <li>La opción "is" del método {{domxref("Document.createElement()")}}: Permite crear una instancia de un elemento HTML estandar que se comporta como un determinado elemento incorporado personalizado registrado.</li> + </ul> + </dd> + <dt>Pseudo-clases CSS</dt> + <dd>Pseudo-clases relacionadas específicamente a elementos personalizados: + <ul> + <li>{{cssxref(":defined")}}: Coincide con cualquier elemento declarado, incluyendo elementos incorporados y elementos personalizados definidos con <code>CustomElementRegistry.define()</code>).</li> + <li>{{cssxref(":host")}}: Selecciona el <em>shadow host</em> del <a href="/en-US/docs/Web/Web_Components/Using_shadow_DOM">shadow DOM</a> conteniendo el CSS que es usado.</li> + <li>{{cssxref(":host()")}}: Selecciona el <em>shadow host</em> del <a href="/en-US/docs/Web/Web_Components/Using_shadow_DOM">shadow DOM</a> conteniendo el CSS que es usado (para que se pueda seleccionar un elemento personalizado desde dentro de su <em>shadow DOM</em>) — pero solo si el selector determinado como el parámetro de la función coincide con el <em>shadow host</em>.</li> + <li>{{cssxref(":host-context()")}}: Selecciona el <em>shadow host</em> del <a href="/en-US/docs/Web/Web_Components/Using_shadow_DOM">shadow DOM</a> conteniendo el CSS que es usado (para que se pueda seleccionar un elemento personalizado desde dentro de su <em>shadow DOM</em>) — pero solo si el selector determinado como el parámetro de la función coincide con el shadow host de los ancestros del sitio desde el cual esta ubicado en la jerarquía del DOM.</li> + </ul> + </dd> + <dd> + <ul> + </ul> + </dd> + <dt>Pseudo-elementos CSS</dt> + <dd>Pseudo-elementos relacionados especificamente a elementos personalizados: + <ul> + <li>{{cssxref("::part")}}: Representa cualquier elemento dentro del <a href="/en-US/docs/Web/Web_Components/Using_shadow_DOM">shadow tree</a> que contiene un atributo {{HTMLAttrxRef("part")}} que coincida.</li> + </ul> + </dd> +</dl> + +<h3 id="Shadow_DOM">Shadow DOM</h3> + +<dl> + <dt>{{domxref("ShadowRoot")}}</dt> + <dd>Representa el nodo raíz de un subárbol de un <em>shadow DOM</em>.</dd> + <dt>{{domxref("DocumentOrShadowRoot")}}</dt> + <dd>Un mixin definiendo características que son disponibles a través de documentos y <em>shadow roots</em>.</dd> + <dt>Extensiones a {{domxref("Element")}}</dt> + <dd>Extensiones a la interfaz <code>Element</code> relacionada al <em>shadow DOM</em>: + <ul> + <li>El método {{domxref("Element.attachShadow()")}} conecta un árbol <em>shadow DOM </em>al elemento especificado.</li> + <li>La propiedad {{domxref("Element.shadowRoot")}} retorna el <em>shadow root</em> acoplado al elemento determinado, o <code>null</code> si no hay un <em>shadow root</em> adjuntado.</li> + </ul> + </dd> + <dt>Adiciones relevantes a {{domxref("Node")}}</dt> + <dd>Adiciones a la interfaz <code>Node</code> relevantes al <em>shadow DOM</em>: + <ul> + <li>El método {{domxref("Node.getRootNode()")}} retorna la raíz del objeto del contexto, que opcionalmente incluye el <em>shadow root</em> si se encuentra disponible.</li> + <li>La propiedad {{domxref("Node.isConnected")}} retorna un boleano indicando si el Nodo esta o no conectado (directamente o indirectamente) al objeto del contexto, es decir, el objeto {{domxref("Document")}} en el caso del DOM normal, o al {{domxref("ShadowRoot")}} en el caso del shadow DOM.</li> + </ul> + </dd> + <dt>Extensiones a {{domxref("Event")}}</dt> + <dd>Extensiones a la interfaz <code>Event</code> relacionada al shadow DOM: + <ul> + <li>{{domxref("Event.composed")}}: Retorna un {{jsxref("Boolean")}} que indica si el evento se va a propagar a través de los límites del <em>shadow DOM </em>hacia el<em> </em>DOM normal (<code>true</code>), o no (<code>false</code>).</li> + <li>{{domxref("Event.composedPath")}}: Retorna la ruta del evento (objetos en los que oyentes serán invocados). Esto no incluye nodos en <em>shadow trees</em> si el <em>shadow root</em> fue creado con {{domxref("ShadowRoot.mode")}} cerrado.</li> + </ul> + </dd> +</dl> + +<h3 id="Plantillas_HTML">Plantillas HTML</h3> + +<dl> + <dt>{{htmlelement("template")}}</dt> + <dd>Contiene un fragmento de HTML que no es renderizado cuando se carga inicialmente un documento que lo contiene, pero puede ser desplegado en tiempo de ejecución usando JavaScript, principalmente usado como la base de la estructura de los elementos personalizados. La interfaz DOM asociada es {{domxref("HTMLTemplateElement")}}.</dd> + <dt>{{htmlelement("slot")}}</dt> + <dd>Un espacio termporal dentro de un componente web que se puede llenar con una plantilla de marcado propia, lo que permite crear árboles DOM separados y presentarlos juntos. La interfaz DOM asociada es {{domxref("HTMLSlotElement")}}.</dd> + <dt>El atributo global HTML <code><a href="/en-US/docs/Web/HTML/Global_attributes/slot">slot</a></code></dt> + <dd>Asigna un slot en un <em>shadow tree</em> de un <em>shadow DOM</em> shadow tree a un elemento.</dd> + <dt>{{domxref("Slotable")}}</dt> + <dd>Un mixin implementado tanto por los nodos {{domxref("Element")}} y {{domxref("Text")}}, definiendo características que les permiten convertirse en el contenido de un elemento {{htmlelement("slot")}}. El mixin define un atributo, {{domxref("Slotable.assignedSlot")}}, el cual retorna una referencia al nodo del slot donde esta insertado.</dd> +</dl> + +<dl> + <dt>Extensiones a {{domxref("Element")}}</dt> + <dd>Extensiones a la interfaz <code>Element</code> relacionadas a slots: + <ul> + <li>{{domxref("Element.slot")}}: Retorna el nombre del slot del <em>shadow DOM</em> adjunto al elemento.</li> + </ul> + </dd> + <dt>Pseudo-elementos de CSS</dt> + <dd>Pseudo-elementos especificamente relacionados a slots: + <ul> + <li>{{cssxref("::slotted")}}: Coincide cualquier contenido que es insertado dentro de un slot.</li> + </ul> + </dd> + <dt>El evento {{event("slotchange")}}</dt> + <dd>Disparado en una instancia {{domxref("HTMLSlotElement")}} (elemento {{htmlelement("slot")}}) cuando el o los nodos contenidos es ese slot cambia.</dd> +</dl> + +<h2 id="Ejemplos">Ejemplos</h2> + +<p>Se están construyendo varios ejemplos en nuestro repositorio de GitHub <a href="https://github.com/mdn/web-components-examples">web-components-examples</a>. Se añadirán más con el tiempo.</p> + +<h2 id="Especificaciones">Especificaciones</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificación</th> + <th scope="col">Estado</th> + <th scope="col">Comentario</th> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG","scripting.html#the-template-element","<template> element")}}</td> + <td>{{Spec2("HTML WHATWG")}}</td> + <td>La definición de {{HTMLElement("template")}}.</td> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG","custom-elements.html#custom-elements","custom elements")}}</td> + <td>{{Spec2("HTML WHATWG")}}</td> + <td>La definición de <a href="/en-US/docs/Web/Web_Components/Using_custom_elements">elementos personalizados HTML (HTML Custom Elements)</a>.</td> + </tr> + <tr> + <td>{{SpecName("DOM WHATWG","#shadow-trees","shadow trees")}}</td> + <td>{{Spec2("DOM WHATWG")}}</td> + <td>La definición de <a href="/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a>.</td> + </tr> + <tr> + <td>{{SpecName("HTML Imports", "", "")}}</td> + <td>{{Spec2("HTML Imports")}}</td> + <td>Definición inicial de <a href="/en-US/docs/Web/Web_Components/HTML_Imports">HTML Imports</a>.</td> + </tr> + <tr> + <td>{{SpecName("Shadow DOM", "", "")}}</td> + <td>{{Spec2("Shadow DOM")}}</td> + <td>Definición inicial de <a href="/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a>.</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidad_de_los_navegadores">Compatibilidad de los navegadores</h2> + +<p><a href="https://twitter.com/polymer/status/1217578939456970754/photo/1"><img alt="Soporte de Componentes Web" src="https://pbs.twimg.com/media/EOW1l5dVAAADJuF?format=jpg&name=large" style="height: 684px; width: 1200px;"></a></p> + +<p>(Imagen tomada de <a href="https://www.webcomponents.org/">webcomponents.org</a>)</p> + +<p>Para revisar detalladamente el soporte para ciertas características (sobre todo en versiones anteriores o navegadores antiguos), se puede consultar las páginas de referencia listadas anteriormente</p> + +<h2 id="Ver_también">Ver también</h2> + +<ul> + <li><a href="https://www.webcomponents.org/">webcomponents.org</a> — Sitio que presenta ejemplos, tutoriales y otra información site featuring web components examples, tutorials, and other information.</li> + <li><a href="https://open-wc.org/">open-wc </a>— Sitio que incluye recomendaciones para el desarrollo, linting, testeo, demos, publicación y automatización de componentes web</li> + <li><a href="https://webcomponents.dev/features/">webcomponents.dev </a>— Sitio que provee de una interfaz de desarrollo online para trabajar con componentes web, ya sea nativamente o con diferentes librerías</li> + <li><a href="https://github.com/hybridsjs/hybrids">Hybrids</a> — Librería para componentes web de código abierto, que favorece objetos simples y funciones puras sobre la sintasis <code>class</code> y <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">this</span></font>. Provee de una sencilla y funcional API para crear elementos personalizados.</li> + <li><a href="https://www.polymer-project.org/">LitElement (Proyecto Polymer)</a> — Marcos de trabajo para componentes web de Google — con un conjunto de polyfills, mejoras y ejemplos. Actualmente es la forma más sencilla de usar componentes web.</li> + <li><a href="https://github.com/devpunks/snuggsi#readme">Snuggsi</a> — Componentes web facilmente en ~1kB <em>incluyedo polyfill</em> — Todo lo que se necesita es un navegador y conocimientos básicos de HTML, CSS y clases de JavaScript para ser productivo.</li> + <li><a href="https://stenciljs.com/">Stencil</a> — Conjunto de herramientas para construir componentes web de sistemas de diseño reusables y escalables.</li> + <li><a href="https://github.com/slimjs/slim.js">Slim.js</a> — Librería para componenetes web de código abierto — una librería con alto rendimiento para la autoría rápida y fácil de componentes; extensible y acoplable y compatible con otros marcos de trabajo</li> +</ul> diff --git a/files/es/web/web_components/using_custom_elements/index.html b/files/es/web/web_components/using_custom_elements/index.html new file mode 100644 index 0000000000..150d906131 --- /dev/null +++ b/files/es/web/web_components/using_custom_elements/index.html @@ -0,0 +1,304 @@ +--- +title: Usando elementos personalizados +slug: Web/Web_Components/Using_custom_elements +tags: + - Autonomos + - Clases + - Guía + - HTML + - Preconstruidos + - elementos personalizados +translation_of: Web/Web_Components/Using_custom_elements +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">Una de las características claves del estándar de Componentes Web es la capacidad de crear elementos personalizados que encapsulan tu funcionalidad en una página HTML, en vez de tener que hacerlo con una larga lista de elementos anidados que juntos proveen una funcionalidad o característica personalizada en una página. Este artículo presenta el uso del API de Elementos Personalizados.</p> + +<div class="note"> +<p><strong>Nota</strong>: Los Elementos Personalizados funcionan por defecto en Firefox, Chrome, y Edge (76). Opera y Safari solo adminten Elementos Personalizados autónomos (que extienden HTMLElement).</p> +</div> + +<h2 id="Vista_de_alto_nivel">Vista de alto nivel</h2> + +<p>El controlador de los elementos personalizados en un documento web es el objeto {{domxref("CustomElementRegistry")}} — este objeto te permite registrar un elemento personalizado en la página, devolver información de qué elementos personalizados se han registrado, etc.</p> + +<p>Para registrar un elemento personalizado en la página, debes usar el método {{domxref("CustomElementRegistry.define()")}} . Éste toma los siguientes argumentos:</p> + +<ul> + <li>Un {{domxref("DOMString")}} que representa el nombre que estás dando al elemento. Nótese que los nombres de los elementos personalizados <a href="https://stackoverflow.com/questions/22545621/do-custom-elements-require-a-dash-in-their-name">deben contener un guión</a> (kebab-case); Los nombres no pueden ser palabras simples.</li> + <li>Un objeto <a href="/en-US/docs/Web/JavaScript/Reference/Classes">class</a> que define el comportamiento del ejemplo.</li> + <li>Opcionalmente, un objeto de opciones que contiene la propiedad <code>extends</code> , que especifica el elemento preconstruido del que hereda (solo es relevante para elementos personalizados preconstruidos; ver la definición más abajo).</li> +</ul> + +<p>Entonces por ejemplo, podríamos definir un elemento personalizado <a href="https://mdn.github.io/web-components-examples/word-count-web-component/">word-count</a> como este:</p> + +<pre class="brush: js notranslate">customElements.define('word-count', WordCount, { extends: 'p' });</pre> + +<p>El elemento se llama <code>word-count</code>, la clase es <code>WordCount</code>, y extiende el elemento {{htmlelement("p")}}.</p> + +<p>Para escribir una clase que defina un elemento personalizado, usamos la sintáxis estándar de ES 2015. Por ejemplo, <code>WordCount</code> está estructurada así:</p> + +<pre class="brush: js notranslate">class WordCount extends HTMLParagraphElement { + constructor() { + // Siempre llamar primero a super en el constructor + super(); + + // La funcionalidad del elemento se escribe aquí + + ... + } +}</pre> + +<p>Esto es solo un ejemplo sencillo, pero aquí se pueden hacer más cosas. Dentro de la clase podemos definir callbacks de ciclo de vida, que se ejecutan en momentos específicos del ciclo de vida del elemento. Por ejemplo, <code>connectedCallback</code> se invoca cada vez que el elemento se añade a un documento, mientras que <code>attributeChangedCallback</code> se invoca cuando uno de los atributos del elemento se ha añadido, quitado o cambiado.</p> + +<p>Aprenderás más sobre estos callbacks en la sección {{anch("Using the lifecycle callbacks")}} más abajo.</p> + +<p>Hay dos tipos de elementos personalizados :</p> + +<ul> + <li><strong>Elementos personalizados autónomos</strong> — estos no heredan de elementos estándar HTML. Se usan estos elementos en una página escribiéndolos literalmente como un elemento HTML nuevo. Por ejemplo <code><popup-info></code>, o <code>document.createElement("popup-info")</code>.</li> + <li><strong>Elementos preconstruidos</strong> <strong>personalizados</strong> heredan de elementos HTML básicos. Para crear un elemento de este tipo, tienes que especificar qué elemento extiende (como se verá en los ejemplos de abajo), y se usan escribiendo el nombre del elemento básico, pero añadiendo un atributo (o propiedad) {{htmlattrxref("is")}} y dándole como valor el nombre del elemento personalizado que se ha desarrollado. Por ejemplo <code><p is="word-count"></code>, o <code>document.createElement("p", { is: "word-count" })</code>.</li> +</ul> + +<h2 id="Trabajando_mediante_algunos_ejemplos_sencillos">Trabajando mediante algunos ejemplos sencillos</h2> + +<p>Llegados a este punto, veamos con más detalle cómo se crean los elementos personalizados, a través de algunos ejemplos.</p> + +<h3 id="Elementos_personalizados_autónomos">Elementos personalizados autónomos</h3> + +<p>Echemos un vistazo al ejemplo de un elemento personalizado autónomo — <code><a href="https://github.com/mdn/web-components-examples/tree/master/popup-info-box-web-component"><popup-info-box></a></code> (ver el <a href="https://mdn.github.io/web-components-examples/popup-info-box-web-component/">ejemplo en vivo</a>). Este ejemplo toma un icono y una cadena de texto, y los incrusta en la página. Cuando el icono toma el foco, se muestra el texto en una caja emergente (popup) de información para proporcionar más información de contexto.</p> + +<p>Para empezar, en un fichero JavaScript se define una clase llamada <code>PopUpInfo</code>, que extiende la clase genérica {{domxref("HTMLElement")}}.</p> + +<pre class="brush: js notranslate">class PopUpInfo extends HTMLElement { + constructor() { + // Siempre llamar primero a super en el constructor + super(); + + // La funcionalidad del elemento se escribe aquí + + ... + } +}</pre> + +<p>El trozo de código anterior contiene un <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/constructor">constructor()</a></code> para la clase, que siempre empieza llamando a <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/super">super()</a></code> de forma que se establezca correctamente el encadenado del prototipo.</p> + +<p>Dentro del constructor, definimos toda la funcionalidad que tendrá el elemento cuando se instancie. En este caso, adjuntamos una shadow root al elemento personalizado, mediante manipulación de DOM creamos la estructura interna del shadow DOM del elemento — que se adjunta a su vez a la shadow root — y finalmente añadimos algo de estilos CSS al shadow root.</p> + +<pre class="brush: js notranslate">// Creamos un shadow root +var shadow = this.attachShadow({mode: 'open'}); + +// Creamos spans +var wrapper = document.createElement('span'); +wrapper.setAttribute('class','wrapper'); +var icon = document.createElement('span'); +icon.setAttribute('class','icon'); +icon.setAttribute('tabindex', 0); +var info = document.createElement('span'); +info.setAttribute('class','info'); + +// Tomamos el contenido del atributo y lo ponemos dentro del span +var text = this.getAttribute('data-text'); +info.textContent = text; + +// Añadimos el icono +var imgUrl; +if(this.hasAttribute('img')) { + imgUrl = this.getAttribute('img'); +} else { + imgUrl = 'img/default.png'; +} +var img = document.createElement('img'); +img.src = imgUrl; +icon.appendChild(img); + +// Creamos un poco de CSS para aplicar al shadow dom +var style = document.createElement('style'); + +style.textContent = '.wrapper {' + +// CSS truncado por brevedad + +// añade los elementos creados al shadow dom + +shadow.appendChild(style); +shadow.appendChild(wrapper); +wrapper.appendChild(icon); +wrapper.appendChild(info);</pre> + +<p>Finalmente, registraremos nuestro elemento en el <code>CustomElementRegistry</code> usando el método <code>define()</code> que mencionamos anteriormente — en los parámetros especificamos el nombre del elemento, y el nombre de la clase que define su funcionalidad::</p> + +<pre class="brush: js notranslate">customElements.define('popup-info', PopUpInfo);</pre> + +<p>Ahora ya está disponible para usarse en nuestra página. En nuestro HTML, lo usamos de esta manera:</p> + +<pre class="brush: html notranslate"><popup-info img="img/alt.png" data-text="Your card validation code (CVC) + is an extra security feature — it is the last 3 or 4 numbers on the + back of your card."></popup-info></pre> + +<div class="note"> +<p><strong>Nota</strong>: Puedes ver el código <a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-web-component/main.js">fuente JavaScript completo</a> aquí.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Nota</strong>: Recuerda que para que los elementos personalizados funcionen, el script que los registra tiene que cargarse después de que el DOM lo interprete. Esto puede hacerse incluyendo un elemento <code><script></code> al final del <code><body></code>, o poniendo el atributo <code>defer</code> en tu elemento <code><script></code>.</p> +</div> + +<h3 id="Estilos_internos_vs._externos">Estilos internos vs. externos</h3> + +<p>En el ejemplo de arriba, aplicamos estilos al Shadow DOM usando el elemento {{htmlelement("style")}} , pero podríamos perfectamente hacerlo referenciando una hoja de estilos externa mediante un elemento {{htmlelement("link")}}.</p> + +<p>Por ejemplo, echemos un vistazo al código de ejemplo de <a href="https://mdn.github.io/web-components-examples/popup-info-box-external-stylesheet/">popup-info-box-external-stylesheet</a> (ver el <a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-external-stylesheet/main.js">código fuente</a>):</p> + +<pre class="brush: js notranslate">// Creamos elemento link para cargar hoja de estilos externa +const linkElem = document.createElement('link'); +linkElem.setAttribute('rel', 'stylesheet'); +linkElem.setAttribute('href', 'style.css'); + +// Añadimos el elemento creado al shadow dom +shadow.appendChild(linkElem);</pre> + +<p>Nótese que los elementos {{htmlelement("link")}} no bloquean el pintado de shadow root, por lo que podría verse un flash o contenido sin estilo (FOUC) mientras se carga la hoja de estilos.</p> + +<p>Muchos navegadores modernos implementan una optimización para etiquetas {{htmlelement("style")}} clonadas de un nodo común o que tienen texto idéntico, que les permite compartir una única hoja de estilo por detrás. Con esta optimización, el rendimiento de estilos externos e internos debería ser parecido.</p> + +<h3 id="Elementos_preconstruidos_personalizados">Elementos preconstruidos personalizados</h3> + +<p>Echemos un vistazo ahora a otro ejemplo de elemento preconstruído personalizado — <a href="https://github.com/mdn/web-components-examples/tree/master/expanding-list-web-component">expanding-list</a> (ver el <a href="https://mdn.github.io/web-components-examples/expanding-list-web-component/">ejemplo en vivo</a>). Este ejemplo convierte cualquier lista sin orden <UL> en un menú expandible/colapsable.</p> + +<p>Primero de todo, definimos nuesta clase, de la misma forma que antes:</p> + +<pre class="brush: js notranslate">class ExpandingList extends HTMLUListElement { + constructor() { + // Siempre llamar primero a super en el constructor + super(); + + // La funcionalidad del elemento se escribe aquí + + ... + } +}</pre> + +<p>No explicaremos la funcionalidad del elemento en detalle aquí, pero puedes descubrir cómo funciona mirando el código fuente. La única diferencia real es que nuestro elemento extiende de la interfaz {{domxref("HTMLUListElement")}}, y no de {{domxref("HTMLElement")}}. Por lo que tiene todas las características de un elemento {{htmlelement("ul")}} además de la funcionalidad que agreguemos nosotros, en vez de ser un elemento autónomo. Esto es lo que lo hace un elemento preconstruido personalizado en vez de uno autónomo.</p> + +<p>Después, registramos el elemento usando el método <code>define()</code> como antes, excepto que esta vez incluimos un objeto de opciones, en el tercer parámetro, que detalla de qué elemento hereda:</p> + +<pre class="brush: js notranslate">customElements.define('expanding-list', ExpandingList, { extends: "ul" });</pre> + +<p>El uso de un elemento preconstruido en un documento web también es algo distinto:</p> + +<pre class="brush: html notranslate"><ul is="expanding-list"> + + ... + +</ul></pre> + +<p>Usas el elemento <code><ul></code> como siempre, pero especificas el nombre del elemento personalizado mediante un atributo <code>is</code> .</p> + +<div class="note"> +<p><strong>Nota</strong>: De nuevo, puedes ver el código <a href="https://github.com/mdn/web-components-examples/blob/master/expanding-list-web-component/main.js">fuente JavaScript completo </a> aquí.</p> +</div> + +<h2 id="Usando_callbacks_de_ciclo_de_vida">Usando callbacks de ciclo de vida</h2> + +<p>Puedes definir varios callbacks dentro de la definición de la clase de un elemento personalizado. Estos callbacks se disparan en distintos puntos del ciclo de vida de elemento:</p> + +<ul> + <li><code>connectedCallback</code>: Se invoca cada vez que se añade un elemento personalizado a un documento. Esto ocurrirá cada vez que el nodo se mueva, y puede suceder antes de que todo el contenido se haya parseado. + + <div class="note"> + <p><strong>Nota</strong>: <code>connectedCallback</code> puede llamarse cuando el elemento ya no esté conectado. Para asegurarse usar {{domxref("Node.isConnected")}}.</p> + </div> + </li> + <li><code>disconnectedCallback</code>: Se invoca cada vez que el elemento se desconecta del DOM del documento.</li> + <li><code>adoptedCallback</code>: Se invoca cada vez que el elemento se mueve a un nuevo documento.</li> + <li><code>attributeChangedCallback</code>: Se invoca cada vez que los atributos del elemento se añaden, quitan o cambian. Deben especificarse previamente en el método estático <code>observedAttributes</code> los atributos que queremos que nos sean notificados.</li> +</ul> + +<p>Echemos un vistazo a un ejemplo de todo esto. El código de abajo se ha tomado del ejemplo <a href="https://github.com/mdn/web-components-examples/tree/master/life-cycle-callbacks">life-cycle-callbacks</a> (ver el <a href="https://mdn.github.io/web-components-examples/life-cycle-callbacks/">ejemplo en vivo</a>). Se trata de un ejemplo trivial que simplemente genera un cuadrado coloreado de un tamaño fijo en la página. El elemento personalizado es algo como esto:</p> + +<pre class="brush: html notranslate"><custom-square l="100" c="red"></custom-square></pre> + +<p>El constructor de la clase es muy simple — adjuntamos un shadow DOM al elemento, y después adjuntamos un {{htmlelement("div")}} vacío y un elemento {{htmlelement("style")}} al shadow root:</p> + +<pre class="brush: js notranslate">var shadow = this.attachShadow({mode: 'open'}); + +var div = document.createElement('div'); +var style = document.createElement('style'); +shadow.appendChild(style); +shadow.appendChild(div);</pre> + +<p>La función clave en este ejemplo es <code>updateStyle()</code> — esta toma un elemento, obtiene su shadow root, busca su elemento <code><style></code>, y añade al estilo {{cssxref("width")}}, {{cssxref("height")}}, y {{cssxref("background-color")}}.</p> + +<pre class="brush: js notranslate">function updateStyle(elem) { + const shadow = elem.shadowRoot; + shadow.querySelector('style').textContent = ` + div { + width: ${elem.getAttribute('l')}px; + height: ${elem.getAttribute('l')}px; + background-color: ${elem.getAttribute('c')}; + } + `; +}</pre> + +<p>Las actualizaciones se manejan mediande los callbacks que se incluyen en la definición de la clase. El método <code>connectedCallback()</code> se ejecuta cada vez que el elemento se añade al DOM — en este instante ejecutamos la función <code>updateStyle()</code> para asegurarnos que el cuadrado se pinta tal y como se definió en sus atributos:</p> + +<pre class="brush: js notranslate">connectedCallback() { + console.log('Custom square element added to page.'); + updateStyle(this); +}</pre> + +<p>Los callbacks <code>disconnectedCallback()</code> y <code>adoptedCallback()</code> simplemente imprimen mensajes a la consola para informarnos cuando el elemento se quita del DOM, o bien se mueve a una página distinta:</p> + +<pre class="brush: js notranslate">disconnectedCallback() { + console.log('Custom square element removed from page.'); +} + +adoptedCallback() { + console.log('Custom square element moved to new page.'); +}</pre> + +<p>El callback <code>attributeChangedCallback()</code> se ejecuta cuando los atributos cambian de alguna forma. Como puedes ver en sus propiedades, es posible actuar sobre atributos individuales, teniendo en cuenta su nombre, y sus valores anterior y nuevo. Sinembargo en este ejemplo, simplemente ejecutamos de nuevo la función <code>updateStyle()</code> para asegurarnos de que el cuadrado tiene el estilo adecuado a sus nuevos valores:</p> + +<pre class="brush: js notranslate">attributeChangedCallback(name, oldValue, newValue) { + console.log('Custom square element attributes changed.'); + updateStyle(this); +}</pre> + +<p>Nótese que el callback <code>attributeChangedCallback()</code> se dispara cuando un atributo cambia y está observándose el atributo. Esto se hace mediante el método <code>static get observedAttributes()</code> dentro de la clase - este debería devolver un array que contiene los nombres de los atributos que se deben observar:</p> + +<pre class="brush: js notranslate">static get observedAttributes() { return ['c', 'l']; }</pre> + +<p>Este código se coloca en la parte de arriba del constructor en nuestro ejemplo.</p> + +<div class="note"> +<p><strong>Nota</strong>: Busca el <a href="https://github.com/mdn/web-components-examples/blob/master/life-cycle-callbacks/main.js">código JavaScript completo </a>aquí.</p> +</div> + +<h2 id="Polyfills_vs._clases">Polyfills vs. clases</h2> + +<p>Polyfills de los elementos personalizados pueden parchear constructores nativos como <code>HTMLElement</code> y otros, y devolver una instancia de una clase diferente de la que se acaba de crear.</p> + +<p>Si necesitas un <code>constructor</code> y una llamada obligatoria a <code>super</code>, recuerda indicar los argumentos opcionales en el constructor y pasarlos a <code>super</code>.</p> + +<pre class="brush: js notranslate">class CustomElement extends HTMLElement { + constructor(...args) { + const self = super(...args); + // self functionality written in here + // self.addEventListener(...) + // return the right context + return self; + } +}</pre> + +<p>Si no necesitar realizar ninguna operación en el constructor, simplemente omítelo, ya que se preservará su comportamiento nativo (ver a continuación).</p> + +<pre class="brush: js notranslate"> constructor(...args) { return super(...args); } +</pre> + +<h2 id="Transpiladores_vs._clases">Transpiladores vs. clases</h2> + +<p>Nótese que las clases ES2015 no pueden transpilarse con Babel 6 o TypeScript para navegadores antiguos. Puedes usar Babel 7 o el plugin <a href="https://www.npmjs.com/package/babel-plugin-transform-builtin-classes">babel-plugin-transform-builtin-classes</a> para Babel 6, y especificar ES2015 como destino (target) en TypeScript en vez de legacy.</p> + +<h2 id="Librerías">Librerías</h2> + +<p>Existen varias librerías que se han construido sobre Web Components con la intención de incrementar el nivel de abstracción cuando se crean elementos personalizados. Algunas de estas librerías son <a href="https://github.com/devpunks/snuggsi" rel="nofollow">snuggsi ツ</a>, <a href="https://x-tag.github.io/" rel="nofollow">X-Tag</a>, <a href="http://slimjs.com/" rel="nofollow">Slim.js</a>, <a href="https://lit-element.polymer-project.org/">LitElement</a>, <a href="https://www.htmlelements.com/">Smart</a>, y <a href="https://stenciljs.com">Stencil</a>.</p> diff --git a/files/es/web/web_components/using_shadow_dom/index.html b/files/es/web/web_components/using_shadow_dom/index.html new file mode 100644 index 0000000000..b660ee7181 --- /dev/null +++ b/files/es/web/web_components/using_shadow_dom/index.html @@ -0,0 +1,199 @@ +--- +title: Usando shadow DOM +slug: Web/Web_Components/Using_shadow_DOM +translation_of: Web/Web_Components/Using_shadow_DOM +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">Un aspecto importante de los componentes Web es la encapsulación — ser capaz de mantener la estructura de marcado, estilo, y comportamiento oculto y separado de otro código en la página para que las diferentes partes no entre en conflicto, y el código pueda permanecer limpio y agradable. El API de DOM Shadow es un parte clave para esto, proporcionando una forma de enlazar un DOM oculto y separado a un elemento. Este artículo cubre los aspectos básicos para utilizar Shadow DOM.</p> + +<div class="note"> +<p><strong>Nota</strong>: Shadow DOM es soportado por defecto en Firefox (63 en adelante), Chrome, Opera, y Safari. Edge también está trabajando en una implemetanción.</p> +</div> + +<h2 id="Vista_de_alto_nivel">Vista de alto nivel</h2> + +<p>Este artículo asume que usted está familiarizado con el concepto de <a href="/en-US/docs/Web/API/Document_Object_Model/Introduction">DOM (Document Object Model)</a> — una estructura en forma de arbol de nodos conectados que representan los diferentes elementos y cadenas de texto que aparecen en un documento de marcado (generalmente un documento HTML en el caso de documentos web). Como ejemplo, considere el siguiente fragmento HTML:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple DOM example</title> + </head> + <body> + <section> + <img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."> + <p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p> + </section> + </body> +</html></pre> + +<p>Este fragmento produce la siguientre estructura de DOM:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14559/dom-screenshot.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p><em>Shadow</em> DOM permite adjuntar arboles DOM ocultos a elementos en el arbol DOM regular — este arbol shadow DOM comienza con un elemento <strong>shadow root,</strong> debajo del cual se puede adjuntar cualquier elemento que desee, de la misma manera que el DOM normal.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15788/shadow-dom.png" style="height: 543px; width: 1138px;"></p> + +<p>Hay algunos conceptos de Shadow DOM que deben ser tomados en cuenta:</p> + +<ul> + <li><strong>Shadow host</strong>: El nodo regular del DOM al que es atado el shadow DOM.</li> + <li><strong>Shadow tree</strong>: El arbol DOM dentro del shadow DOM.</li> + <li><strong>Shadow boundary</strong>: El punto en el que el shadow DOM termina y el DOM regular comienza.</li> + <li><strong>Shadow root</strong>: El nodo raiz del arbol Shadow.</li> +</ul> + +<p>Puede manipular los nodos del 'shadow DOM' de la misma manera que los nodos del arbol DOM regular. Por ejemplo, agregando hijos o estableciendo atributos, dando estilo a nodos individuales utilizando element.style.foo, o agregando estilo a todo el árbol de 'shadow DOM' dentro del elemento <style>. La diferencia es que nada del código dentro de un 'shadow DOM' puede afectar a nada fuera de él, lo que permite una encapsulación práctica.</p> + +<p>Cabe destacar que el shadow DOM no es algo nuevo — los exploradores lo han usado por un largo tiempo para encapsular la estructura interna de un elemento. Piensa por ejemplo en un elemento {{htmlelement("video")}}, con los controles predeterminados del explorador a la vista. Todo lo que ves en el DOM es el elemento <code><video></code>, pero este contiene una serie de botones y otros controles dentro de su shadow DOM. Las especificaciones del shadow DOM fueron hechas para que seas capaz de manipular el shadow DOM de tus elementos personalizados.</p> + +<h2 id="Uso_básico">Uso básico</h2> + +<p>Puede adjuntar un 'shadow root' a cualquier elemento utilizando el método {{domxref ("Element.attachShadow ()")}}. Éste toma como parámetro un objeto que contiene una propiedad — modo — con dos posibles valores: 'open' o 'closed'.</p> + +<pre class="brush: js notranslate">let shadow = elementRef.attachShadow({mode: 'open'}); +let shadow = elementRef.attachShadow({mode: 'closed'});</pre> + +<p><code>open</code> siginifica que puede acceder al shadow DOM usando JavaScript en el contexto principal de la página. Por ejemplo, usando la propiedad {{domxref("Element.shadowRoot")}}:</p> + +<pre class="brush: js notranslate">let myShadowDom = myCustomElem.shadowRoot;</pre> + +<p>If you attach a shadow root to a custom element with <code>mode: closed</code> set, you won't be able to access the shadow DOM from the outside — <code>myCustomElem.shadowRoot</code> returns <code>null</code>. This is the case with built in elements that contain shadow DOMs, such as <code><video></code>.</p> + +<div class="note"> +<p><strong>Note</strong>: As <a href="https://blog.revillweb.com/open-vs-closed-shadow-dom-9f3d7427d1af">this blog post shows</a>, it is actually fairly easy to work around closed shadow DOMs, and the hassle to completely hide them is often more than it's worth.</p> +</div> + +<p>If you are attaching a shadow DOM to a custom element as part of its constructor (by far the most useful application of the shadow DOM), you would use something like this:</p> + +<pre class="brush: js notranslate">let shadow = this.attachShadow({mode: 'open'});</pre> + +<p>When you've attached a shadow DOM to an element, manipulating it is a matter of just using the same DOM APIs as you use for the regular DOM manipulation:</p> + +<pre class="brush: js notranslate">var para = document.createElement('p'); +shadow.appendChild(para); +// etc.</pre> + +<h2 id="Working_through_a_simple_example">Working through a simple example</h2> + +<p>Now let's walk through a simple example to demonstrate the shadow DOM in action inside a custom element — <code><a href="https://github.com/mdn/web-components-examples/tree/master/popup-info-box-web-component"><popup-info-box></a></code> (see a <a href="https://mdn.github.io/web-components-examples/popup-info-box-web-component/">live example</a> also). This takes an image icon and a text string, and embeds the icon into the page. When the icon is focused, it displays the text in a pop up information box to provide further in-context information. To begin with, in our JavaScript file we define a class called <code>PopUpInfo</code>, which extends <code>HTMLElement</code>:</p> + +<pre class="brush: js notranslate">class PopUpInfo extends HTMLElement { + constructor() { + // Always call super first in constructor + super(); + + // write element functionality in here + + ... + } +}</pre> + +<p>Inside the class definition we define the element's constructor, which defines all the functionality the element will have when an instance of it is instantiated.</p> + +<h3 id="Creating_the_shadow_root">Creating the shadow root</h3> + +<p>We first attach a shadow root to the custom element:</p> + +<pre class="brush: js notranslate">// Create a shadow root +var shadow = this.attachShadow({mode: 'open'});</pre> + +<h3 class="brush: js" id="Creating_the_shadow_DOM_structure">Creating the shadow DOM structure</h3> + +<p class="brush: js">Next, we use some DOM manipulation to create the element's internal shadow DOM structure:</p> + +<pre class="brush: js notranslate">// Create spans +var wrapper = document.createElement('span'); +wrapper.setAttribute('class','wrapper'); +var icon = document.createElement('span'); +icon.setAttribute('class','icon'); +icon.setAttribute('tabindex', 0); +var info = document.createElement('span'); +info.setAttribute('class','info'); + +// Take attribute content and put it inside the info span +var text = this.getAttribute('text'); +info.textContent = text; + +// Insert icon +var imgUrl; +if(this.hasAttribute('img')) { + imgUrl = this.getAttribute('img'); +} else { + imgUrl = 'img/default.png'; +} +var img = document.createElement('img'); +img.src = imgUrl; +icon.appendChild(img); +</pre> + +<h3 class="brush: js" id="Styling_the_shadow_DOM">Styling the shadow DOM</h3> + +<p class="brush: js">After that we create a {{htmlelement("style")}} element and populate it with some CSS to style it:</p> + +<pre class="brush: js notranslate">// Create some CSS to apply to the shadow dom +var style = document.createElement('style'); + +style.textContent = ` +.wrapper { + position: relative; +} + +.info { + font-size: 0.8rem; + width: 200px; + display: inline-block; + border: 1px solid black; + padding: 10px; + background: white; + border-radius: 10px; + opacity: 0; + transition: 0.6s all; + position: absolute; + bottom: 20px; + left: 10px; + z-index: 3; +} + +img { + width: 1.2rem; +} + +.icon:hover + .info, .icon:focus + .info { + opacity: 1; +}`; + +</pre> + +<h3 id="Attaching_the_shadow_DOM_to_the_shadow_root">Attaching the shadow DOM to the shadow root</h3> + +<p>The final step is to attach all the created elements to the shadow root:</p> + +<pre class="brush: js notranslate">// attach the created elements to the shadow dom +shadow.appendChild(style); +shadow.appendChild(wrapper); +wrapper.appendChild(icon); +wrapper.appendChild(info);</pre> + +<h3 id="Using_our_custom_element">Using our custom element</h3> + +<p>Once the class is defined, using the element is as simple as defining it, and putting it on the page, as explained in <a href="/en-US/docs/Web/Web_Components/Using_custom_elements">Using custom elements</a>:</p> + +<pre class="brush: js notranslate">// Define the new element +customElements.define('popup-info', PopUpInfo);</pre> + +<pre class="brush: html notranslate"><<span class="pl-ent">popup-info</span> <span class="pl-e">img</span>=<span class="pl-s"><span class="pl-pds">"</span>img/alt.png<span class="pl-pds">"</span></span> <span class="pl-e">text</span>=<span class="pl-s"><span class="pl-pds">"</span>Your card validation code (CVC) is an extra + security feature — it is the last 3 or 4 + numbers on the back of your card.<span class="pl-pds">"</span></span>></pre> + +<div> +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/Web_Components/Using_custom_elements">Using custom elements</a></li> + <li><a href="/en-US/docs/Web/Web_Components/Using_templates_and_slots">Using templates and slots</a></li> +</ul> +</div> diff --git a/files/es/web/web_components/using_templates_and_slots/index.html b/files/es/web/web_components/using_templates_and_slots/index.html new file mode 100644 index 0000000000..d8047d325b --- /dev/null +++ b/files/es/web/web_components/using_templates_and_slots/index.html @@ -0,0 +1,335 @@ +--- +title: Usando plantillas y slots +slug: Web/Web_Components/Using_templates_and_slots +tags: + - Componentes Web + - Template + - shadow dom + - slot +translation_of: Web/Web_Components/Using_templates_and_slots +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">Este artículo explica como puedes usar los elementos {{htmlelement("template")}} y {{htmlelement("slot")}} para crear una plantilla flexible que luego puede ser usada para rellenar el shadow DOM de un componente web.</p> + +<h2 id="La_verdad_acerca_del_elemento_<template>">La verdad acerca del elemento <template></h2> + +<p>Cuando tienes que reutilizar las mismas estructuras de lenguaje de marcado repetidas veces en una página web, tiene sentido utilizar algún tipo de plantilla en lugar de repetir la misma estructura una y otra vez. Esto ya era posible hacerlo antes, pero ahora es mucho mas fácil con el elemento HTML {{htmlelement("template")}} (que está bien soportado en los navegadores modernos). Este elemento y su contenido no son renderizados en el DOM, pero pueden ser referenciados vía JavaScript.</p> + +<p>Echemos un vistazo a un ejemplo sencillo:</p> + +<pre class="brush: html"><template id="my-paragraph"> + <p>Mi párrafo</p> +</template></pre> + +<p>Esto no aparecerá en tu página hasta que hagas una referencia a él con JavaScript y luego lo agregues al DOM, usando algo parecido a lo siguiente:</p> + +<pre class="brush: js">let template = document.getElementById('my-paragraph'); +let templateContent = template.content; +document.body.appendChild(templateContent);</pre> + +<p>Aunque de una manera simple, ya puedes empezar a ver su utilidad.</p> + +<h2 id="Usando_el_elemento_<template>_con_componentes_web">Usando el elemento <template> con componentes web</h2> + +<p>Las plantillas son útiles por si mismas, pero trabajan aún mejor con componentes web. Definamos un componente web que use nuestra plantilla como el contenido de su shadow DOM. Lo nombraremos <code><my-paragraph></code>:</p> + +<pre class="brush: js">customElements.define('my-paragraph', + class extends HTMLElement { + constructor() { + super(); + let template = document.getElementById('my-paragraph'); + let templateContent = template.content; + + const shadowRoot = this.attachShadow({mode: 'open'}) + .appendChild(templateContent.cloneNode(true)); + } +})</pre> + +<p>El punto clave a tener en cuenta aquí es que agregamos un clon del contenido de la plantilla al shadow root creado usando el método {{domxref("Node.cloneNode()")}}.</p> + +<p>Y debido a que estamos agregando su contenido a un shadow DOM, podemos incluir cierta información de estilo dentro de la plantilla en un elemento {{htmlelement("style")}}, que luego se encapsula dentro del elemento personalizado. Esto no funcionaría si nosotros solo lo agregásemos al DOM estandar.</p> + +<p>Por ejemplo:</p> + +<pre class="brush: html"><template id="my-paragraph"> + <style> + p { + color: white; + background-color: #666; + padding: 5px; + } + </style> + <p>Mi párrafo</p> +</template></pre> + +<p>Ahora podemos usarlo simplemente agregándolo a nuestro documento HTML:</p> + +<pre class="brush: html"><my-paragraph></my-paragraph> +</pre> + +<div class="note"> +<p><strong>Nota: </strong>Las plantillas están bien soportadas en los navegadores: la API del Shadow DOM es compatible por defecto con Firefox (version 63 en adelante), Chrome, Opera y Safari, Edge está trabajando en una implementación.</p> +</div> + +<h2 id="Añadiendo_flexibilidad_con_el_elemento_<slot>">Añadiendo flexibilidad con el elemento <slot></h2> + +<p>Hasta aquí bien, pero el elemento no es muy flexible. Solo podemos mostrar una parte de texto dentro de él, lo que quiere decir que, hasta el momento, es menos útil que un párrafo normal. Podemos mostrar diferente texto en cada instancia de elemento de una forma declarativa agradable usando el elemento {{htmlelement("slot")}}. Este tiene un soporte más limitado que el elemento {{htmlelement("template")}}, disponible desde Chrome 53, Opera 40, Safari 10, Firefox 59, pero aún no disponible en Edge.</p> + +<p>Los slots son identificados por su atributo <code>name</code>, y te permiten definir marcadores de posición en tu plantilla que pueden rellenarse con cualquier fragmento de marcado cuando el elemento es usado.</p> + +<p>Así que, si queremos agregar un slot dentro de nuestro ejemplo sencillo, podemos actualizar el elemento de párrafo de la plantilla de la siguiente manera:</p> + +<pre class="brush: html"><p><slot name="my-text"><span class="tlid-translation translation" lang="es"><span title="">Mi texto predeterminado</span></span></slot></p></pre> + +<p>Si el contenido del slot no está definido cuando el elemento se agrega al marcado, o si el navegador no soporta el elemento slot, <code><my-paragraph></code> solo contiene el texto alternativo "<span class="tlid-translation translation" lang="es"><span title="">Mi texto predeterminado</span></span>".</p> + +<p>Para definir el contenido de un slot, incluimos una estructura HTML dentro del elemento <code><my-paragraph></code> con un atributo {{htmlattrxref("slot")}} cuyo valor es igual al nombre del slot que queremos rellenar. Al igual que<span class="tlid-translation translation" lang="es"><span title=""> antes, esto puede ser cualquier cosa, por ejemplo:</span></span></p> + +<pre class="brush: html"><my-paragraph> + <span slot="my-text"><span class="tlid-translation translation" lang="es"><span title="">¡Tengamos un texto diferente!</span></span></span> +</my-paragraph></pre> + +<p>o</p> + +<pre class="brush: html"><my-paragraph> + <ul slot="my-text"> + <li><span class="tlid-translation translation" lang="es"><span title="">¡Tengamos un texto diferente!</span></span></li> + <li>¡En una lista!</li> + </ul> +</my-paragraph> +</pre> + +<div class="note"> +<p><strong>Nota: </strong>Los elementos que pueden ser insertados en los slots son conocidos como {{domxref("Slotable")}}; cuando un elemento ha sido insertado en un slot, se dice que fue <em>eslotado </em>por su término en inlgés <em>slotted.</em></p> +</div> + +<div class="blockIndicator note"> +<p><strong>Nota:</strong> Un {{HTMLElement("slot")}} <span class="tlid-translation translation" lang="es"><span title="">sin nombre se rellenará con todos los nodos secundarios de nivel superior del elemento personalizado que no tengan el atributo </span></span> {{htmlattrxref("slot")}}. <span class="tlid-translation translation" lang="es"><span title="">Esto incluye nodos de texto.</span></span></p> +</div> + +<p>Y eso es todo nuestro ejemplo sencillo. Si quieres jugar con él un poco más, puedes encontrarlo en <a href="https://github.com/mdn/web-components-examples/tree/master/simple-template">GitHub</a> (también puedes <a href="https://mdn.github.io/web-components-examples/simple-template/">verlo en vivo</a>).</p> + +<h2 id="Un_ejemplo_más_completo">Un ejemplo más completo</h2> + +<p>Para finalizar el artículo, veamos algo menos trivial.</p> + +<p>El siguiente conjunto de fragmentos de código muestra cómo usar {{HTMLElement("slot")}} junto con {{HTMLElement("template")}} y algo de JavaScript para:</p> + +<ul> + <li>crear un elemento <strong><code><element-details></code></strong> con <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> en su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a></li> + <li>diseñe el elemento <strong><code><element-details></code></strong> de forma que, cuando se use en documentos, sea renderizado desde la composición del contenido del elemento junto con el contenido de su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root,</a> es decir, se utilizan partes del contenido del elemento para rellenar el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> de los <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a></li> +</ul> + +<p>Observa que es técnicamente posible usar el elemento {{HTMLElement("slot")}} sin un elemento {{HTMLElement("template")}}, por ejemplo, dentro de un elemento {{HTMLElement("div")}} normal, y aun así tomar ventaja de los indicadores de posición de el elemento {{HTMLElement("slot")}} para el contenido del <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a>, y al hacerlo puedes evitar el problema de tener que acceder primero a la propiedad <code>content</code> del elemento de la plantilla y clonarlo. Sin embargo, por lo general, es más práctico agregar slots dentro de un elemento {{HTMLElement("template")}}, ya que es poco probable que necesites definir un patrón basado en un elemento ya renderizado.</p> + +<p>Además, incluso si no está renderizado, el propósito del contenedor como plantilla debería ser semánticamente más claro cuando se usa el elemento {{HTMLElement("template")}}. Además, el elemento {{HTMLElement("template")}} puede tener elementos agregados directamente a él, como {{HTMLElement("td")}}, que desaparecerían al añadirse a un {{HTMLElement ("div")}}.</p> + +<div class="note"> +<p><strong>Nota: </strong>Puedes encontrar el ejemplo completo en <a href="https://github.com/mdn/web-components-examples/tree/master/element-details">element-details </a>(también lo puedes<a href="https://github.com/mdn/web-components-examples/tree/master/element-details"> ver en vivo</a>)</p> +</div> + +<h3 id="Creando_una_plantilla_con_algunos_elementos_<slot>">Creando una plantilla con algunos elementos <slot></h3> + +<p>En primer lugar, usamos el elemento {{HTMLElement("slot")}} dentro de un elemento {{HTMLElement("template")}} para crear un nuevo <a href="/en-US/docs/Web/API/DocumentFragment">fragmento de documento</a> de tipo "element-details-template" que contiene algunos <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con el atributo name</a>:</p> + +<pre class="brush: html"><template id="element-details-template"> + <style> + details {font-family: "Open Sans Light",Helvetica,Arial} + .name {font-weight: bold; color: #217ac0; font-size: 120%} + h4 { margin: 10px 0 -8px 0; } + h4 span { background: #217ac0; padding: 2px 6px 2px 6px } + h4 span { border: 1px solid #cee9f9; border-radius: 4px } + h4 span { color: white } + .attributes { margin-left: 22px; font-size: 90% } + .attributes p { margin-left: 16px; font-style: italic } + </style> + <details> + <summary> + <span> + <code class="name">&lt;<slot name="element-name">NECESITA NOMBRE</slot>&gt;</code> + <i class="desc"><slot name="description">NECESITA DESCRIPCIÓN</slot></i> + </span> + </summary> + <div class="attributes"> + <h4><span>Atributos</span></h4> + <slot name="attributes"><p>Ninguno</p></slot> + </div> + </details> + <hr> +</template> +</pre> + +<p>Ese elemento {{HTMLElement("template")}} tiene varias características.</p> + +<ul> + <li>El {{HTMLElement ("template")}} tiene un elemento {{HTMLElement ("style")}} con un conjunto de estilos CSS ajustados al ámbito del fragmento de documento que {{HTMLElement ("template")}} crea.</li> + <li>El elemento {{HTMLElement("template")}} usa {{HTMLElement("slot")}} y su atributo {{htmlattrxref("name", "slot")}} para hacer tres <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con el atributo name</a>: + <ul> + <li><code><slot name="element-name"></code></li> + <li><code><slot name="description"></code></li> + <li><code><slot name="attributes"></code></li> + </ul> + </li> + <li>El elemento {{HTMLElement("template")}} envuelve los <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> dentro de un elemento {{HTMLElement("details")}}.</li> +</ul> + +<h3 id="Crear_un_nuevo_elemento_<element-details>_desde_el_elemento_<template>">Crear un nuevo elemento <element-details> desde el elemento <template></h3> + +<p>A continuación, crearemos un nuevo elemento personalizado llamado <strong><code><element-details></code></strong> y usaremos {{DOMXref("Element.attachShadow")}} para anclarlo, como su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>, a ese fragmento de documento que creamos anteriormente con nuestro elemento {{HTMLElement("template")}}. Usa exactamente el mismo patrón que vimos antes en el ejemplo sencillo.</p> + +<pre class="brush: js">customElements.define('element-details', + class extends HTMLElement { + constructor() { + super(); + var template = document + .getElementById('element-details-template') + .content; + const shadowRoot = this.attachShadow({mode: 'open'}) + .appendChild(template.cloneNode(true)); + } +}) +</pre> + +<h3 id="Usando_el_elemento_<element-details>_con_slots_con_el_atributo_name">Usando el elemento <element-details> con slots con el atributo name</h3> + +<p>Ahora tomaremos el elemento <strong><code><element-details></code></strong> para usarlo en nuestro documento.</p> + +<pre class="brush: html"><element-details> + <span slot="element-name">slot</span> + <span slot="description">Un marcador de posición dentro de un + componente web que los usuarios pueden rellenar con su propio marcado, + con el efecto de componer diferentes árboles DOM + juntos.</span> + <dl slot="attributes"> + <dt>name</dt> + <dd>El atributo name del slot.</dd> + </dl> +</element-details> + +<element-details> + <span slot="element-name">template</span> + <span slot="description">Un mecanismo para guardar contenido + en el lado cliente que no se renderiza cuando la página se + carga sino que posteriormente se puede instanciar en + tiempo de ejecución usando JavaScript.</span> +</element-details> +</pre> + +<p><span class="tlid-translation translation" lang="es"><span title="">Observa estos puntos sobre el fragmento anterior</span></span>:</p> + +<ul> + <li>El fragento tiene dos instancias de elementos <strong><code><element-details></code></strong> que usan el atributo {{htmlattrxref("slot")}} para referenciar los <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> <code>"element-name"</code> y <code>"description"</code> que colocamos en el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> del <code><element-details></code></li> + <li>Solo el primero de esos dos elementos <strong><code><element-details></code></strong> hace referencia a los <code>"attributes"</code> de <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name. </a>El segundo elemento <code><strong><element-details</strong>></code> carece de cualquier referencia a <code>"attributes"</code> de <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a>.</li> + <li>El primer elemento <code><<strong>element-details></strong></code> está referenciando los <code>"attributes"</code> de <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> usando un elemento {{HTMLElement("dl")}} con {{HTMLElement("dt")}} y {{HTMLElement("dd")}} como hijos.</li> +</ul> + +<h3 id="Añadamos_algunos_estilos">Añadamos algunos estilos</h3> + +<p>Como toque final, añadiremos algunos estilos CSS a los ellementos {{HTMLElement("dl")}}, {{HTMLElement("dt")}}, y {{HTMLElement("dd")}} en el documento:</p> + +<pre class="brush: css"> dl { margin-left: 6px; } + dt { font-weight: bold; color: #217ac0; font-size: 110% } + dt { font-family: Consolas, "Liberation Mono", Courier } + dd { margin-left: 16px } +</pre> + +<div class="hidden"> +<pre class="brush: css">body { margin-top: 47px }</pre> +</div> + +<h3 id="Resultado">Resultado</h3> + +<p>Finalmente, juntemos todos los fragmentos y veamos cómo se ve el resultado renderizado.</p> + +<p>{{ EmbedLiveSample('full_example', '300','400','https://mdn.mozillademos.org/files/14553/element-details.png','') }}</p> + +<p>Observa los siguientes puntos del resultado renderizado:</p> + +<ul> + <li>Aún cuando las instancias del elemento <strong><code><element-details></code></strong> en el documento no usan directamente el elemento {{HTMLElement("details")}}, se renderizan usando {{HTMLElement("details")}} porque el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> hace que ellos se rellenen.</li> + <li>En la salida de {{HTMLElement ("details")}}, el contenido de los elementos <strong><code><element-details></code></strong> llena los <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>. En otras palabras, el árbol DOM de los elementos <strong><code><element-details></code></strong> se compone junto con el contenido del <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>.</li> + <li>Para ambos elementos <strong><code><element-details></code></strong>, un encabezado de <strong>Attributes</strong> se añade automáticamente desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> antes de la posición <code>"attributes"</code> del <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a>.</li> + <li>Ya que el primer elemento <strong><code><element-details></code></strong> tiene un elemento {{HTMLElement("dl")}} que hace referencia explicita al <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> <code>"attributes"</code> desde su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>, el contenido de ese {{HTMLElement("dl")}} reemplaza el <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> <code>"attributes"</code> desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a></li> + <li>Ya que el segundo elemento <strong><code><element-details></code></strong> no hace referencia explícita al <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> <code>"attributes"</code> desde su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>, su contenido se rellena con el contenido predeterminado desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>.</li> +</ul> + +<div class="hidden"> +<h5 id="full_example">full example</h5> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <title>ejemplo de slot</title> + <style> + + dl { margin-left: 6px; } + dt { font-weight: bold; color: #217ac0; font-size: 110% } + dt { font-family: Consolas, "Liberation Mono", Courier } + dd { margin-left: 16px } + + </style> + </head> + <body> + <template id="element-details-template"> + <style> + details {font-family: "Open Sans Light",Helvetica,Arial} + .name {font-weight: bold; color: #217ac0; font-size: 120%} + h4 { margin: 10px 0 -8px 0; } + h4 span { background: #217ac0; padding: 2px 6px 2px 6px } + h4 span { border: 1px solid #cee9f9; border-radius: 4px } + h4 span { color: white } + .attributes { margin-left: 22px; font-size: 90% } + .attributes p { margin-left: 16px; font-style: italic } + </style> + <details> + <summary> + <span> + <code class="name">&lt;<slot name="element-name">NECESITA NOMBRE</slot>&gt;</code> + <i class="desc"><slot name="description">NECESITA DESCRIPCIÓN</slot></i> + </span> + </summary> + <div class="attributes"> + <h4><span>Attributos</span></h4> + <slot name="attributes"><p>Ninguno</p></slot> + </div> + </details> + <hr> + </template> + + <element-details> + <span slot="element-name">slot</span> + <span slot="description">Un marcador de posición dentro de un + componente web que los usuarios pueden rellenar con su propio marcado, + con el efecto de componer diferentes árboles DOM + juntos.</span> + <dl slot="attributes"> + <dt>name</dt> + <dd>El atributo name del slot.</dd> + </dl> + </element-details> + + <element-details> + <span slot="element-name">template</span> + <span slot="description">Un mecanismo para guardar contenido + en el lado cliente que no se renderiza cuando la página se + carga sino que posteriormente se puede instanciar en + tiempo de ejecución usando JavaScript.</span> + </element-details> + + <script> + customElements.define('element-details', + class extends HTMLElement { + constructor() { + super(); + const template = document + .getElementById('element-details-template') + .content; + const shadowRoot = this.attachShadow({mode: 'open'}) + .appendChild(template.cloneNode(true)); + } + }) + </script> + </body> +</html></pre> +</div> |