Los elementos personalizados permiten a los desarrolladores web definir nuevas etiquetas HTML, extender las existentes y crear componentes web reutilizables.
Con los elementos personalizados, los desarrolladores web pueden crear nuevas etiquetas HTML, refuerce las etiquetas HTML existentes o extienda los componentes de otros desarrolladores. creado. La API es la base de la Web componentes. Ofrece una experiencia basada en estándares para crear componentes reutilizables usando solo JS/HTML/CSS estándar. El resultado es menos código, modular el código y más reutilización nuestras aplicaciones.
Introducción
El navegador nos proporciona una herramienta excelente para estructurar aplicaciones web. Es llamada HTML. Quizás hayas oído hablar de él. Es declarativo, portátil, y fácil de usar. Como puede ser el lenguaje HTML, su vocabulario y la extensibilidad son limitados. La vivencia HTML estándar nunca tuvo una forma de asociar automáticamente el comportamiento de JS con tu lenguaje de marcado... hasta ahora.
Los elementos personalizados son la respuesta a la modernización de HTML, completando el espacio piezas y agrupar la estructura con el comportamiento. Si HTML no proporciona la a un problema, podemos crear un elemento personalizado que lo haga. Personalizado le enseñan nuevos trucos al navegador y, a la vez, preservan los beneficios del HTML.
Cómo definir un elemento nuevo
Para definir un nuevo elemento HTML, necesitamos la potencia de JavaScript.
El global customElements
se usa para definir un elemento personalizado y enseñar.
al navegador sobre una nueva etiqueta. Llama a customElements.define()
con el nombre de la etiqueta.
que deseas crear y un class
de JavaScript que extienda la HTMLElement
base.
Ejemplo: se define un panel lateral para dispositivos móviles, <app-drawer>
:
class AppDrawer extends HTMLElement {...}
window.customElements.define('app-drawer', AppDrawer);
// Or use an anonymous class if you don't want a named constructor in current scope.
window.customElements.define('app-drawer', class extends HTMLElement {...});
Ejemplo de uso:
<app-drawer></app-drawer>
Es importante recordar que el uso de un elemento personalizado no es diferente del
con un <div>
o cualquier otro elemento. Las instancias se pueden declarar en la página,
de forma dinámica en JavaScript, adjuntar objetos de escucha de eventos, etcétera.
para ver más ejemplos.
Define la API de JavaScript de un elemento
La funcionalidad de un elemento personalizado se define con un ES2015.
class
que extiende HTMLElement
. Extender HTMLElement
garantiza que el elemento personalizado
hereda toda la API del DOM y se refiere a todas las propiedades o métodos que agregues al
forman parte de la interfaz del DOM del elemento. Básicamente, usa la clase para
crear una API pública de JavaScript para tu etiqueta.
Ejemplo: Definición de la interfaz del DOM de <app-drawer>
:
class AppDrawer extends HTMLElement {
// A getter/setter for an open property.
get open() {
return this.hasAttribute('open');
}
set open(val) {
// Reflect the value of the open property as an HTML attribute.
if (val) {
this.setAttribute('open', '');
} else {
this.removeAttribute('open');
}
this.toggleDrawer();
}
// A getter/setter for a disabled property.
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
// Reflect the value of the disabled property as an HTML attribute.
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
}
// Can define constructor arguments if you wish.
constructor() {
// If you define a constructor, always call super() first!
// This is specific to CE and required by the spec.
super();
// Setup a click listener on <app-drawer> itself.
this.addEventListener('click', e => {
// Don't toggle the drawer if it's disabled.
if (this.disabled) {
return;
}
this.toggleDrawer();
});
}
toggleDrawer() {
// ...
}
}
customElements.define('app-drawer', AppDrawer);
En este ejemplo, creamos un panel lateral que tiene una propiedad open
, disabled
y un método toggleDrawer()
. También refleja propiedades como HTML
atributos.
Una característica interesante de los elementos personalizados es que this
dentro de una definición de clase
hace referencia al elemento DOM en sí, es decir, la instancia de la clase. En nuestra
Por ejemplo, this
hace referencia a <app-drawer>
. Así ((...)) es como el elemento puede
adjunta un objeto de escucha click
a sí mismo. Además, no estarás limitado a los objetos de escucha de eventos.
Toda la API del DOM está disponible dentro del código del elemento. Usa this
para acceder a la
propiedades del elemento, inspeccionar sus elementos secundarios (this.children
), consultar nodos
(this.querySelectorAll('.items')
), etcétera
Reglas sobre la creación de elementos personalizados
- El nombre de un elemento personalizado debe contener un guion (-). Es decir,
<x-tags>
,<my-element>
y<my-awesome-app>
son nombres válidos, mientras que<tabs>
y<foo_bar>
no. Este requisito es para que el analizador de HTML pueda a distinguir entre los elementos personalizados y los normales. También garantiza que los usuarios compatibilidad cuando se agregan etiquetas nuevas a HTML. - No puedes registrar la misma etiqueta más de una vez. Si intentas hacerlo,
arroja una
DOMException
. Una vez que informaste al navegador sobre una nueva etiqueta, que la modifica. Sin devoluciones. - Los elementos personalizados no pueden cerrarse automáticamente porque HTML solo permite unos pocos
elementos
se cierren por sí solos. Escribir siempre una etiqueta de cierre
(
<app-drawer></app-drawer>
).
Reacciones de elementos personalizados
Un elemento personalizado puede definir hooks de ciclo de vida especiales para ejecutar código durante interesantes de su existencia. Estos se denominan elementos personalizados reacciones.
Nombre | Se llama cuando |
---|---|
constructor |
Una instancia del elemento es
crean o actualizan. Útil para inicializar
el estado, la configuración de objetos de escucha de eventos
crear un shadow DOM
Consulta la
especificación
para conocer las restricciones sobre lo que puedes hacer en constructor .
|
connectedCallback |
Se llama cada vez que el se inserta en el DOM. Son útiles para ejecutar código de configuración, como recuperación de recursos o renderización. En general, debes intentar retrasar el trabajo hasta ahora. |
disconnectedCallback |
Se llama cada vez que se quita el elemento del DOM. Útil para ejecutando el código de limpieza. |
attributeChangedCallback(attrName, oldVal, newVal) |
Se llama cuando se ha observado un atributo observado.
agregar, quitar, actualizar o reemplazar. También se llama para valores iniciales
Cuando el analizador crea un elemento.
actualizado. Nota: Solo
atributos enumerados en la propiedad observedAttributes
para recibir esta devolución de llamada.
|
adoptedCallback |
El
se trasladó el elemento personalizado a un document nuevo (p.ej.,
alguien llamado document.adoptNode(el) ).
|
Las devoluciones de llamada de reacción son síncronas. Si alguien llama a el.setAttribute()
en tu elemento, el navegador llamará de inmediato a attributeChangedCallback()
.
Del mismo modo, recibirás un disconnectedCallback()
justo después de que tu elemento esté listo.
Se quita del DOM (p.ej., el usuario llama a el.remove()
).
Ejemplo: Se agregaron reacciones de elementos personalizados a <app-drawer>
:
class AppDrawer extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// ...
}
connectedCallback() {
// ...
}
disconnectedCallback() {
// ...
}
attributeChangedCallback(attrName, oldVal, newVal) {
// ...
}
}
Define reacciones cuando tengan sentido. Si tu elemento es lo suficientemente complejo
y abre una conexión con IndexedDB en connectedCallback()
, haz lo necesario
trabajo de limpieza en disconnectedCallback()
. Pero ten cuidado. No puedes confiar en tu
el elemento completamente del DOM en todas las circunstancias. Por ejemplo:
Nunca se llamará a disconnectedCallback()
si el usuario cierra la pestaña.
Propiedades y atributos
Cómo reflejar propiedades en atributos
Es común que las propiedades HTML reflejen su valor en el DOM como un
atributo HTML. Por ejemplo, cuando los valores de hidden
o id
se cambian en
JS:
div.id = 'my-id';
div.hidden = true;
los valores se aplican al DOM activo como atributos:
<div id="my-id" hidden>
Esto se denomina "propiedades de reflexión para atributos”. Casi todas las propiedades en HTML hacen esto. ¿Por qué? Los atributos también son útiles para configurar un elemento de forma declarativa y ciertas APIs, como la accesibilidad y CSS los selectores dependen de los atributos para funcionar.
Reflejar una propiedad es útil en cualquier lugar en el que desees conservar el DOM del elemento representada en sincronización con su estado de JavaScript. Una razón por la que quizás quieras reflejan una propiedad es para que se aplique un estilo definido por el usuario cuando cambie el estado de JS.
Recuerda nuestro <app-drawer>
. Es posible que un usuario de este componente quiera fundirlo.
o impedir la interacción del usuario cuando está inhabilitado:
app-drawer[disabled] {
opacity: 0.5;
pointer-events: none;
}
Cuando se cambia la propiedad disabled
en JS, queremos que ese atributo sea
agregar al DOM para que coincida el selector del usuario. El elemento puede proporcionar que
comportamiento reflejando el valor en un atributo con el mismo nombre:
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
// Reflect the value of `disabled` as an attribute.
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
this.toggleDrawer();
}
Observar cambios en los atributos
Los atributos HTML son una forma conveniente para que los usuarios declaren el estado inicial:
<app-drawer open disabled></app-drawer>
Los elementos pueden reaccionar a los cambios de atributos definiendo un
attributeChangedCallback
El navegador llamará a este método para cada cambio
a los atributos enumerados en el array observedAttributes
.
class AppDrawer extends HTMLElement {
// ...
static get observedAttributes() {
return ['disabled', 'open'];
}
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
}
// Only called for the disabled and open attributes due to observedAttributes
attributeChangedCallback(name, oldValue, newValue) {
// When the drawer is disabled, update keyboard/screen reader behavior.
if (this.disabled) {
this.setAttribute('tabindex', '-1');
this.setAttribute('aria-disabled', 'true');
} else {
this.setAttribute('tabindex', '0');
this.setAttribute('aria-disabled', 'false');
}
// TODO: also react to the open attribute changing.
}
}
En el ejemplo, se establecen atributos adicionales en el objeto <app-drawer>
cuando un elemento
Se cambió el atributo disabled
. Aunque no lo estamos haciendo aquí, podrías
también usar la attributeChangedCallback
para mantener una propiedad JS sincronizada con su
.
Actualizaciones de elementos
HTML progresivamente mejorado
Ya aprendimos que los elementos personalizados se definen llamando
customElements.define()
Pero esto no significa que deba definir y registrar un
un elemento personalizado todo a la vez.
Los elementos personalizados se pueden usar antes de registrar su definición.
La mejora progresiva es una característica de los elementos personalizados. En otras palabras, puedes
declarar varios elementos <app-drawer>
en la página y nunca invocar
customElements.define('app-drawer', ...)
hasta mucho más tarde. Esto se debe a que el
el navegador da a los posibles elementos personalizados un tratamiento diferente al de los elementos
etiquetas. El proceso de llamar a define()
y otorgar un permiso existente
con una definición de clase se llama “actualizaciones de elementos”.
Para saber cuándo se define el nombre de una etiqueta, puedes usar
window.customElements.whenDefined()
Devuelve una promesa que se resuelve cuando
se define el elemento.
customElements.whenDefined('app-drawer').then(() => {
console.log('app-drawer defined');
});
Ejemplo: Retrasa el trabajo hasta que se actualice un conjunto de elementos secundarios
<share-buttons>
<social-button type="twitter"><a href="...">Twitter</a></social-button>
<social-button type="fb"><a href="...">Facebook</a></social-button>
<social-button type="plus"><a href="...">G+</a></social-button>
</share-buttons>
// Fetch all the children of <share-buttons> that are not defined yet.
let undefinedButtons = buttons.querySelectorAll(':not(:defined)');
let promises = [...undefinedButtons].map((socialButton) => {
return customElements.whenDefined(socialButton.localName);
});
// Wait for all the social-buttons to be upgraded.
Promise.all(promises).then(() => {
// All social-button children are ready.
});
Contenido definido por el elemento
Los elementos personalizados pueden administrar su propio contenido mediante las APIs del DOM dentro el código del elemento. Las reacciones son útiles para esto.
Ejemplo: Crea un elemento con HTML predeterminado:
customElements.define('x-foo-with-markup', class extends HTMLElement {
connectedCallback() {
this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
}
// ...
});
La declaración de esta etiqueta producirá lo siguiente:
<x-foo-with-markup>
<b>I'm an x-foo-with-markup!</b>
</x-foo-with-markup>
// TODO: DevSite - Se quitó la muestra de código porque usaba controladores de eventos intercalados
Cómo crear un elemento que use Shadow DOM
Shadow DOM ofrece a un elemento una forma de poseer, representar y aplicar diseño a una parte de un DOM independiente del resto de la página. ¡Diablos! Incluso podrías esconder Toda la app en una sola etiqueta:
<!-- chat-app's implementation details are hidden away in Shadow DOM. -->
<chat-app></chat-app>
Para usar Shadow DOM en un elemento personalizado, llama a this.attachShadow
dentro de tu
constructor
let tmpl = document.createElement('template');
tmpl.innerHTML = `
<style>:host { ... }</style> <!-- look ma, scoped styles -->
<b>I'm in shadow dom!</b>
<slot></slot>
`;
customElements.define('x-foo-shadowdom', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// Attach a shadow root to the element.
let shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(tmpl.content.cloneNode(true));
}
// ...
});
Ejemplo de uso:
<x-foo-shadowdom>
<p><b>User's</b> custom text</p>
</x-foo-shadowdom>
<!-- renders as -->
<x-foo-shadowdom>
#shadow-root
<b>I'm in shadow dom!</b>
<slot></slot> <!-- slotted content appears here -->
</x-foo-shadowdom>
Texto personalizado del usuario
// TODO: DevSite - Se quitó la muestra de código porque usaba controladores de eventos intercalados
Cómo crear elementos a partir de un <template>
Para quienes no conocen, la <template>
elemento
te permite declarar fragmentos del DOM que se analizan, están inertes al cargar la página y
se puede activar más adelante en el entorno de ejecución. Es otra primitiva de API en la Web
de la familia de componentes. Las plantillas son marcadores de posición ideales para declarar el
de un elemento personalizado.
Ejemplo: registrar un elemento con contenido de Shadow DOM creado a partir de un
<template>
:
<template id="x-foo-from-template">
<style>
p { color: green; }
</style>
<p>I'm in Shadow DOM. My markup was stamped from a <template>.</p>
</template>
<script>
let tmpl = document.querySelector('#x-foo-from-template');
// If your code is inside of an HTML Import you'll need to change the above line to:
// let tmpl = document.currentScript.ownerDocument.querySelector('#x-foo-from-template');
customElements.define('x-foo-from-template', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
let shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(tmpl.content.cloneNode(true));
}
// ...
});
</script>
Estas pocas líneas de código tienen una gran capacidad. Veamos los puntos clave el:
- Definiremos un nuevo elemento en HTML:
<x-foo-from-template>
- El Shadow DOM del elemento se crea a partir de un
<template>
- El DOM del elemento es local del elemento gracias al Shadow DOM.
- La CSS interna del elemento se define en función del elemento gracias al Shadow DOM.
Estoy en Shadow DOM. Mi marca se selló a partir de una <template>.
// TODO: DevSite - Se quitó la muestra de código porque usaba controladores de eventos intercalados
Cómo aplicar diseño a un elemento personalizado
Incluso si tu elemento define su propio estilo usando Shadow DOM, los usuarios pueden aplicar ajustes de diseño tu elemento personalizado desde su página. Estos se denominan "estilos definidos por el usuario".
<!-- user-defined styling -->
<style>
app-drawer {
display: flex;
}
panel-item {
transition: opacity 400ms ease-in-out;
opacity: 0.3;
flex: 1;
text-align: center;
border-radius: 50%;
}
panel-item:hover {
opacity: 1.0;
background: rgb(255, 0, 255);
color: white;
}
app-panel > panel-item {
padding: 5px;
list-style: none;
margin: 0 7px;
}
</style>
<app-drawer>
<panel-item>Do</panel-item>
<panel-item>Re</panel-item>
<panel-item>Mi</panel-item>
</app-drawer>
Es posible que te preguntes cómo funciona la especificidad de CSS si el elemento tiene estilos. definidos dentro de Shadow DOM. En términos de especificidad, prevalecen los estilos del usuario. Ellos anular siempre el diseño definido por el elemento. Consulta la sección Cómo crear un elemento que usa Shadow DOM.
Cómo aplicar diseño previo a elementos no registrados
Antes de que un elemento se actualice, puede orientarse a él en CSS mediante el
Pseudoclase :defined
. Esto es útil para aplicar estilo previo a un componente. Para
ejemplo, puedes evitar el diseño u otro FOUC visual ocultando las imágenes
de los componentes y atenuarlos
cuando se definan.
Ejemplo: oculta <app-drawer>
antes de que se defina:
app-drawer:not(:defined) {
/* Pre-style, give layout, replicate app-drawer's eventual styles, etc. */
display: inline-block;
height: 100vh;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
Después de que se define <app-drawer>
, el selector (app-drawer:not(:defined)
)
ya no coincide.
Cómo extender elementos
La API de Custom Elements es útil para crear nuevos elementos HTML, pero también útil para extender otros elementos personalizados o incluso el HTML integrado del navegador.
Extiende un elemento personalizado
La extensión de otro elemento personalizado se realiza extendiendo su definición de clase.
Ejemplo: crea <fancy-app-drawer>
que extienda <app-drawer>
:
class FancyDrawer extends AppDrawer {
constructor() {
super(); // always call super() first in the constructor. This also calls the extended class' constructor.
// ...
}
toggleDrawer() {
// Possibly different toggle implementation?
// Use ES2015 if you need to call the parent method.
// super.toggleDrawer()
}
anotherMethod() {
// ...
}
}
customElements.define('fancy-app-drawer', FancyDrawer);
Cómo extender elementos HTML nativos
Supongamos que deseas crear un <button>
más atractivo. En lugar de replicar el
y la funcionalidad de <button>
, una mejor opción es
mejoran los elementos existentes
con elementos personalizados.
Un elemento integrado personalizado es aquel que extiende uno de los las etiquetas HTML integradas del navegador. El beneficio principal de ampliar un es obtener todas sus funciones (propiedades del DOM, métodos, accesibilidad). No hay mejor forma de escribir una Web progresiva que mejorar progresivamente el código HTML existente de los elementos de una sola vez.
Para extender un elemento, deberás crear una definición de clase que herede
de la interfaz del DOM correcta. Por ejemplo, un elemento personalizado que extiende
<button>
debe heredar contenido de HTMLButtonElement
en lugar de HTMLElement
.
De manera similar, un elemento que extiende <img>
debe extender HTMLImageElement
.
Ejemplo, extendiendo <button>
:
// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class FancyButton extends HTMLButtonElement {
constructor() {
super(); // always call super() first in the constructor.
this.addEventListener('click', e => this.drawRipple(e.offsetX, e.offsetY));
}
// Material design ripple animation.
drawRipple(x, y) {
let div = document.createElement('div');
div.classList.add('ripple');
this.appendChild(div);
div.style.top = `${y - div.clientHeight/2}px`;
div.style.left = `${x - div.clientWidth/2}px`;
div.style.backgroundColor = 'currentColor';
div.classList.add('run');
div.addEventListener('transitionend', (e) => div.remove());
}
}
customElements.define('fancy-button', FancyButton, {extends: 'button'});
Observa que la llamada a define()
cambia ligeramente cuando se extiende un código nativo.
. El tercer parámetro obligatorio le indica al navegador qué etiqueta estás
sin extender. Esto es necesario porque muchas etiquetas HTML comparten el mismo DOM.
interfaz de usuario. <section>
, <address>
y <em>
(entre otros) comparten
HTMLElement
; tanto <q>
como <blockquote>
comparten HTMLQuoteElement
; Y así sucesivamente.
Si especificas {extends: 'blockquote'}
, se indica al navegador que estás creando un
se incendió <blockquote>
en lugar de <q>
. Consulta el archivo HTML
especificación
para acceder a la lista completa de interfaces de DOM de HTML.
Los consumidores de un elemento integrado personalizado pueden usarlo de varias maneras. Pueden
Para declararlo, agrega el atributo is=""
en la etiqueta nativa:
<!-- This <button> is a fancy button. -->
<button is="fancy-button" disabled>Fancy button!</button>
Crea una instancia en JavaScript:
// Custom elements overload createElement() to support the is="" attribute.
let button = document.createElement('button', {is: 'fancy-button'});
button.textContent = 'Fancy button!';
button.disabled = true;
document.body.appendChild(button);
También puedes usar el operador new
:
let button = new FancyButton();
button.textContent = 'Fancy button!';
button.disabled = true;
Aquí hay otro ejemplo que extiende <img>
.
Ejemplo, extendiendo <img>
:
customElements.define('bigger-img', class extends Image {
// Give img default size if users don't specify.
constructor(width=50, height=50) {
super(width * 10, height * 10);
}
}, {extends: 'img'});
Los usuarios declaran este componente de la siguiente manera:
<!-- This <img> is a bigger img. -->
<img is="bigger-img" width="15" height="20">
o crea una instancia en JavaScript:
const BiggerImage = customElements.get('bigger-img');
const image = new BiggerImage(15, 20); // pass constructor values like so.
console.assert(image.width === 150);
console.assert(image.height === 200);
Otros detalles
Elementos desconocidos frente a elementos personalizados sin definir
El lenguaje HTML es flexible y flexible para trabajar. Por ejemplo, puedes declarar
<randomtagthatdoesntexist>
en una página y el navegador está perfectamente satisfecho.
aceptarlo. ¿Por qué funcionan las etiquetas no estándar? La respuesta es:
especificación
lo permite. Los elementos que la especificación no define se analizan como
HTMLUnknownElement
No ocurre lo mismo con los elementos personalizados. Se analizan los posibles elementos personalizados.
como HTMLElement
si se crearon con un nombre válido (incluye un “-”). Tú
puedes verificar esto en un navegador compatible con elementos personalizados. Inicia la consola:
Ctrl + Mayúsculas + J (o Cmd + Opt + J en Mac) y pega el
las siguientes líneas de código:
// "tabs" is not a valid custom element name
document.createElement('tabs') instanceof HTMLUnknownElement === true
// "x-tabs" is a valid custom element name
document.createElement('x-tabs') instanceof HTMLElement === true
Referencia de la API
El global de customElements
define métodos útiles para trabajar con conjuntos
o de terceros.
define(tagName, constructor, options)
Define un nuevo elemento personalizado en el navegador.
Ejemplo
customElements.define('my-app', class extends HTMLElement { ... });
customElements.define(
'fancy-button', class extends HTMLButtonElement { ... }, {extends: 'button'});
get(tagName)
Con un nombre de etiqueta de elemento personalizado válido, muestra el constructor del elemento.
Muestra undefined
si no se registró ninguna definición del elemento.
Ejemplo
let Drawer = customElements.get('app-drawer');
let drawer = new Drawer();
whenDefined(tagName)
Muestra una promesa que se resuelve cuando se define el elemento personalizado. Si el botón ya está definido, resuélvelo de inmediato. Se rechaza si el nombre de la etiqueta no es un nombre válido para el elemento personalizado.
Ejemplo
customElements.whenDefined('app-drawer').then(() => {
console.log('ready!');
});
Historial y compatibilidad del navegador
Si has estado siguiendo los componentes web durante los últimos años,
sepa que Chrome 36 y versiones posteriores implementaron una versión de la API de Custom Elements que usa
document.registerElement()
en lugar de customElements.define()
. Ya está
considerada una versión obsoleta del estándar, llamada v0.
customElements.define()
es el nuevo interés y qué son los proveedores de navegadores
empezando a implementar. Se llama Custom Elements v1.
Si estás interesado en la especificación anterior v0, echa un vistazo a los html5rocks artículo.
Navegadores compatibles
Chrome 54 (estado), Safari 10.1 (estado) y Firefox 63 (estado) tiene Custom Elements v1 Edge comenzó y desarrollo.
Para detectar elementos personalizados, verifica la existencia de
window.customElements
:
const supportsCustomElementsV1 = 'customElements' in window;
Polyfill
Hasta que la compatibilidad con navegadores esté ampliamente disponible, existe una polyfill independiente disponible para Custom Elements v1. Sin embargo, recomendamos usar webcomponents.js cargador para cargar de manera óptima los polyfills de los componentes web. El cargador Usa la detección de funciones para cargar de forma asíncrona solo los rellenos de polyfills necesarios. que requiere el navegador.
Instálalo:
npm install --save @webcomponents/webcomponentsjs
Uso:
<!-- Use the custom element on the page. -->
<my-element></my-element>
<!-- Load polyfills; note that "loader" will load these async -->
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js" defer></script>
<!-- Load a custom element definitions in `waitFor` and return a promise -->
<script type="module">
function loadScript(src) {
return new Promise(function(resolve, reject) {
const script = document.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
WebComponents.waitFor(() => {
// At this point we are guaranteed that all required polyfills have
// loaded, and can use web components APIs.
// Next, load element definitions that call `customElements.define`.
// Note: returning a promise causes the custom elements
// polyfill to wait until all definitions are loaded and then upgrade
// the document in one batch, for better performance.
return loadScript('my-element.js');
});
</script>
Conclusión
Los elementos personalizados nos proporcionan una nueva herramienta para definir nuevas etiquetas HTML en el navegador y
crear componentes reutilizables. Combínalos con la otra plataforma nueva.
primitivas, como Shadow DOM y <template>
, y empezamos a ver la gran
imagen de componentes web:
- Es compatible con varios navegadores (estándar de la Web) para crear y extender componentes reutilizables.
- No requiere una biblioteca ni un framework para comenzar. ¡JS/HTML convencionales por la victoria!
- Proporciona un modelo de programación conocido. Es solo DOM/CSS/HTML.
- Funciona bien con otras nuevas funciones de plataformas web (Shadow DOM,
<template>
, CSS). propiedades personalizadas, etc.) - Se integra por completo con las Herramientas para desarrolladores del navegador.
- Aprovecha las funciones de accesibilidad existentes.