Просто зайдите в npm и введите что-нибудь вроде «datepicker». Вы увидите что-то вроде этого:

react-datepicker
angular-datepicker
vue-datepicker
vue-the-very-last-datepicker
vue-the-very-last-datepicker-v2
...

Средство выбора даты для всех фреймворков от Vue до Angular и до React… Это действительно распространенная проблема в мире Javascript.

Разве не было бы замечательно иметь единственное средство выбора даты, которое можно было бы использовать с любой библиотекой или фреймворком?

Веб-компоненты спешат на помощь!

Технология, лежащая в основе веб-компонентов, позволяет вам создавать свой собственный элемент изначально, без использования какой-либо структуры (!), в браузере и использовать его в своем документе так же, как любой другой элемент HTML, как <input> или <button>

Это большое преимущество, особенно для создания элементов, которые должны использоваться совместно между проектами, в которых используются разные фреймворки, или в проектах, где не требуется сложный фреймворк, но вы все равно хотите иметь некоторую структуру.

4 строительных блока веб-компонентов

Веб-компоненты представляют собой совокупность следующих четырех технологий:

  1. Тег HTML<template>
  2. Custom Elements API
  3. Shadow Dom
  4. Модули ES

Давайте объясним четыре строительных блока, создав нашу собственную кнопку веб-компонента.

›› Исходный код и пример можно найти здесь ›› https://playcode.io/347575?tabs=my-button.js,preview,console

1.Шаблоны: содержимое <template> не отображается браузером, но вы все равно можете ссылаться на него в Javascript. Благодаря этому он отлично подходит для контента, который вы хотите использовать несколько раз в разных местах, и идеально подходит для использования в веб-компонентах.

Давайте создадим простой HTML-документ index.html со следующим шаблоном для простой кнопки внутри:

<html>
<head></head>
<body>
<template id="myButton">
 <style>
      div {  
           background: red; 
           color: white; 
           padding: 1em; 
           text-align: center; 
     } 
</style>
 <div>Click me</div>
</template>
</body>
</html>

Если вы откроете файл в браузере, ничего не должно отображаться должным образом.

2. API пользовательских элементов: API пользовательских элементов позволяет объединить весь код, необходимый для вашего веб-компонента, в один класс и определить имя тега для вашего элемента.

class MyButton extends HTMLElement {
constructor() {
   super.constructor();
}
}
customElements.define('my-button', MyButton);

С customElements.define мы определяем имя нашего элемента и соответствующий класс. Имя должно иметь знак -, а класс должен быть наследником HTMLElement.

Теперь вместо того, чтобы помещать тег шаблона непосредственно в основной документ, мы добавим его в наш только что созданный файл javascript следующим образом:

const template = document.createElement('template'); 
template.innerHTML = `
 <style>
     div {  
           background: red; 
           color: white; 
           padding: 1em; 
           text-align: center; 
     }
 </style>
 <div>Click me</div>
`;
class MyButton extends HTMLElement {
constructor() {
   super.constructor();
}
}
customElements.define('my-button', MyButton);

Таким образом, у нас может быть все в одном модуле. На следующем этапе мы добавляем содержимое нашего шаблона к нашему элементу. Для этого сначала рассмотрим теневой дом.

3.Shadow Dom Shadow Dom позволяет вам инкапсулировать ваши стили и структуру разметки. Это позволяет отделить код вашего веб-компонента от остальной части документа. Никаких рамок. Просто чистая технология браузера.

Это круто.

Вам нужно добавить явное прикрепление теневого объекта к вашему элементу следующим образом:

const template = document.createElement('template'); 
template.innerHTML = `
 <style>
     div {  
           background: red; 
           color: white; 
           padding: 1em; 
           text-align: center; 
     }
 </style>
 <div>Click me</div>
`;
class MyButton extends HTMLElement {
constructor() {
   super.constructor();
   this.attachShadow({mode: 'open'}); // <--- attaching shadow dom!
}
}
customElements.define('my-button', MyButton);

Теперь мы добавим содержимое шаблона в наш теневой дом:

const template = document.createElement('template'); 
template.innerHTML = `
 <style>
     div {  
           background: red; 
           color: white; 
           padding: 1em; 
           text-align: center; 
     }
 </style>
 <div>Click me</div>
`;
class MyButton extends HTMLElement {
constructor() {
   super.constructor();
   this.attachShadow({mode: 'open'});
   this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('my-button', MyButton);

Как видите, мы используем template.content.cloneNode(true) для клонирования содержимого шаблона, которое затем присоединяем к нашему теневому домену.

Разметка и стили доступны только в нашем компоненте.

Давайте поговорим о том, как использовать кнопку веб-компонента в основном документе.

4. Модули ES вы можете импортировать свой веб-компонент, чтобы использовать его в других веб-компонентах, или просто импортировать его в свой основной документ index.html сверху, используя <script src="my-button.js type="module"></script>:

<html>
  <head>
    <script src="my-button.js" type="module"></script>
  </head>
<body>
<my-button onclick="alert('hi')"></mybutton>
</body>
</html>

Слот

Что, если мы хотим разрешить пользователю добавлять собственный текст к кнопке вместо фиксированного текста «Нажми меня»? Как в следующем примере:

<my-button>You can click me, sir.</my-button>

Вот тут-то и пригодятся слоты:

Элемент HTML <slot> - часть технологического пакета Веб-компоненты - это заполнитель внутри веб-компонента, который вы можете заполнить собственной разметкой […]

Https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot

Таким образом, мы можем добавить <slot></slot> в наш шаблон в том месте, где мы хотим, чтобы пользовательский текст отображался.

В нашем случае мы заменяем текст «Нажми меня» на <slot></slot>:

const template = document.createElement('template'); 
template.innerHTML = `
 <style>
     div {  
           background: red; 
           color: white; 
           padding: 1em; 
           text-align: center; 
     }
 </style>
<!-- we've replaced the text with <slot>-->
<div><slot></slot></div> 
`;
class MyButton extends HTMLElement {
constructor() {
   super.constructor();
   this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('my-button', MyButton);

Теперь мы можем добавить произвольный текст к кнопке:

<html>
  <head>
    <script src="my-button.js" type="module"></script>
    <style>my-button { margin: 1em; }</style>
  </head>
<body>
  
<my-button onclick="alert('hi');">You can click me, sir</my-button>
<my-button onclick="alert('hello');">Banana</my-button>
<my-button onclick="alert('hey');">Okaaay!</my-button>
</body>
</html>

Я также добавил еще несколько кнопок и событий щелчка с окнами предупреждений, чтобы протестировать кнопки.

Вы создали свою первую кнопку веб-компонента!

Я горжусь тобой, сынок.

Посмотрите полный исходный код и демонстрацию здесь: https://playcode.io/347575?tabs=my-button.js,preview,console