Dentro de un componente personalizado definido con las etiquetas <template> y <slot> , un elemento secundario puede obtener el elemento principal que es el componente personalizado y luego usar esta referencia de elemento para acceder a funciones y variables definidas por la clase.
Sin embargo, ¿cómo puede un elemento secundario saber qué elemento es el componente personalizado?
La plantilla en sí está contenida en un DOM oculto. Al renderizar un componente personalizado en la página, este DOM oculto se clona y adjunta al componente personalizado como su anfitrión.
Los elementos que están insertados en el componente personalizado, sin embargo, parece que no pueden decir que el árbol de nodos al que está conectado provienen de un nodo DOM oculto que se clonó, y no pueden decir qué elemento en el árbol DOM actual es el personalizado de nivel superior componente a menos que itere a través de cada parentNode para verificar si tienen un shadowRoot .
¿Cuál es la forma de permitir que un elemento secundario dentro de un componente personalizado acceda a las funciones y variables de clase del componente personalizado?
customElements.define("my-comp", class extends HTMLElement { creationTimestamp; constructor() { super(); let template = document.getElementById('my-template'); let templateContent = template.content; const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.appendChild(templateContent.cloneNode(true)); this.creationTimestamp = Date.now(); } }) <html> <template id="my-template"> I'm a new custom component using slots with value <slot name="slot1">default</slot> <button onclick="console.log(this.parentNode.host.creationTimestamp)">Print timestamp at Template level</button> </template> <my-comp> <span slot="slot1"> slotted value <div> <button onclick="console.log(this.parentNode.parentNode.parentNode.creationTimestamp)">Print timestamp</button> </div> </span> </my-comp> </html>Ahora entiendo. Quiere prevenir:
let timeStamp = this.parentNode.parentNode.parentNode.creationTimestamp;
Hay varias respuestas de StackOverflow que abordan esto:
Deje que el niño encuentre un padre.
En control: niño
¡Imita el estándar JS .closest(selector) que no perfora shadowRoots!
con una función personalizada de closestElement(selector) :
Función getRootNode.closest() del elemento personalizado que cruza varios límites de shadowDOM (principal)
Hacer que el padre le diga algo a un niño
En control: padre
por una inmersión recursiva en shadowRoots:
¿Cómo puedo obtener todo el HTML en un documento o nodo que contiene elementos shadowRoot?
Deje que el padre responda a una llamada de un niño
En control: ambos Child envían Evento, Parent necesita escuchar
Los componentes web que se comunican mediante eventos personalizados no pueden enviar datos
Las reglas simples que uso para el desacoplamiento son:
Padre a hijo: enlace de datos unidireccional o atributos HTML5 para pasar datos y llamar a child.func() para realizar acciones.
De niño a padre: el niño activa un evento. Los padres escuchan ese evento. Debido al burbujeo de eventos , puede tener un número arbitrario de padres que recojan ese evento sin esfuerzo adicional.
Este patrón también lo utilizan los componentes web estándar ( input , cuadro de textbox , etc.). También permite pruebas sencillas ya que no tiene que burlarse del padre.
Este fue el patrón recomendado descrito por la biblioteca Polymer , que era/es un contenedor sobre WebComponents. Desafortunadamente, no puedo encontrar ese artículo específico que describió este patrón.
En el siguiente ejemplo, el padre escucha los eventos de los hijos y llama funciones sobre sí mismo para afectar su estado, o funciones sobre los hijos para hacer que hagan algo. Ninguno de los niños sabe sobre el padre.