Safari не поддерживает пользовательские встроенные элементы и совместимость с ними
Браузер Safari не поддерживает пользовательские встроенные элементы, только автономные пользовательские элементы.
Давайте уточним, cуществует два вида пользовательских элементов(веб-компонентов):
- Автономные пользовательские элементы – «полностью новые» элементы, расширяющие абстрактный класс
HTMLElement
. - Пользовательские встроенные элементы – элементы, расширяющие встроенные, например кнопку
HTMLButtonElement
и т.п.
Поддержка браузерами 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