mrssea

Safari не поддерживает пользовательские встроенные элементы и совместимость с ними

Браузер Safari не поддерживает пользовательские встроенные элементы, только автономные пользовательские элементы.

Давайте уточним, cуществует два вида пользовательских элементов(веб-компонентов):

  1. Автономные пользовательские элементы – «полностью новые» элементы, расширяющие абстрактный класс HTMLElement.
  2. Пользовательские встроенные элементы – элементы, расширяющие встроенные, например кнопку HTMLButtonElement и т.п.


Поддержка Custom Elements

Поддержка браузерами Custom Elements

То есть Safari по умолчанию поддерживает только следующие веб-компоненты в формате HTML:

  <ui-tips></ui-tips>
  <ui-drop></ui-drop>
  <ui-tab></ui-tab>
  <ui-lighttip></ui-lighttip>

Веб-компоненты, расширяющие собственные элементы HTML с помощью атрибута is, не поддерживаются:

 <input is="ui-color">
 <select is="ui-select"></select>
 <form is="ui-form"></form>
 <table is="ui-table"></table>

Из-за этого возникает проблема: UI-компоненты станут слишком многословными и муторными, если они могут быть реализованы только с использованием автономныХ пользовательских элементов.

Таким образом, лучшее решение — сделать так, чтобы браузер Safari также поддерживал разработку встроенных веб-компонентов.

Как это сделать?

Polyfill для встроенных веб-компонентов

Решение относительно простое, есть специальный полифилл, для тех случаев, когда поддерживаются автономные веб-компоненты, но не встроенные веб-компоненты, в основном для браузера Safari.

index.js — это несжатая версия, а es.js — сжатая версия.

Конечно же, правильнее было бы определять, поддерживает ли браузер пользователя встроенные веб-компоненты:

 class AnyClass extends HTMLBRElement {
  constructor () {
    super();

    this.someMethod = true;
  }
}

if (!customElements.get('any-class')) {
  customElements.define('any-class', AnyClass, {
    extends: 'br'
  });
}
const isSupportBuildIn = document.createElement('br', {
  is: 'any-class'
}).someMethod;

Значение isSupportBuildIn будет true, если браузер поддерживает встроенные веб-компоненты, и undefined, если браузер не поддерживает.

Оптимизированный код JS можно посмотреть тут.

Проблемы с поддержкой

Этот Polyfill действительно удивителен, исходный код веб-компонентов не нуждается в каких-либо изменениях, функция компонента отлично поддерживается в браузере Safari, и все компоненты работают хорошо.

Но уже при использовании обнаруживается проблема, когда компоненты передаются со ссылками.

Например, у нас есть следующий код:

  <script src="safari-polyfill.js">
  <script type="module" src="my-components.js">
  <script type="module">
    myComponent.someMethod();
  </script>

Метод myComponent.someMethod() отлично работает в браузерах, поддерживающих встроенные веб-компоненты. В то же время в Safari он сообщает об ошибке, и undefined не может быть выполнен как функция.

Причина этого в том, что реализация safari-polyfill.js имеет ограничение, из-за которого инициализация пользовательских элементов происходит позже, чем в нативных браузерах.

То есть в Safari при выполнении метода myComponent.someMethod() элемент myComponent еще не стал встроенным веб-компонентом.

В результате выполнение завершится ошибкой.

Можно использовать обходной путь: инициировать пользовательское событие 'connected' в функции connectedCallback (браузер вызывает этот метод при добавлении элемента в документ), чтобы элемент уже был разделен на компоненты, когда код выполняется путем привязки события connected.

  connectedCallback () {
   this.dispatchEvent(new CustomEvent('connected'), {
     detail: {
       type: 'my-components'
     }
   });
 }

и тогда наш код будет выглядеть так:

  <script src="safari-polyfill.js">
  <script type="module" src="my-components.js">
  <script type="module">
    myComponent.addEventListener('connected', function () {
	    this.someMethod();
	});
  </script>

Это гарантирует, что веб-компонент уже будет инициализирован к моменту выполнения метода someMethod().

Ссылки по теме:
1. Оригинал статьи https://www.sobyte.net/post/2021-08/safari-buildin-custom-element-polyfill/


Последняя редакция 28 января, 2023 в 05:01