создавать собственные элементы в iframe

Поскольку импорт HTML еще недостаточно хорошо поддерживается (например, Firefox не планирует этого делать), я попытался имитировать его использование при импорте пользовательских элементов через iframe.

Я пытался сделать это путем загрузки сценария в iframe, который определяет настраиваемый элемент в верхнем контексте просмотра; а после этого iframe можно было даже удалить из документа. Причина, по которой я пытался это сделать, заключается в том, что я хотел бы динамически определять настраиваемые элементы в соответствии с информацией, которую я получаю на стороне клиента; и эти настраиваемые элементы используют шаблоны, которые будут использоваться в теневой модели DOM.

Я предпочитаю использовать шаблоны вместо создания теневого DOM в сценарии, чтобы иметь чистый код; вот почему я хотел бы имитировать функциональность импорта с помощью iframe со всеми шаблонами, а не просто загружать скрипт, в котором создается теневой DOM.

Однако способ, который я пробовал, не работает (проверено в google chrome и firefox):

// iframe.js

class XAElement extends HTMLElement{
 constructor(){
  super()
  // Any customization here
 }
 // Any other methods for functionality
}
top.customElements.define('x-a', XAElement)

Разрешено ли определять пользовательские элементы верхнего контекста просмотра в iframe?

Примечание. Файл iframe.html - это любой файл HTML, который загружает этот сценарий; а файл index.html (в котором возникает ошибка) - это любой файл, загружающий iframe iframe.html.

Примечание 2: я получаю ошибку afer super(); однако, если я прокомментирую последнюю строку (в которой я собираюсь определить настраиваемый элемент), ошибки не произойдет.


person Raúl Arturo Chávez Sarmiento    schedule 17.02.2019    source источник
comment
Вы пытаетесь объявить класс настраиваемого элемента в контексте iframe, но вы определяете настраиваемый элемент в верхнем контейнере, который представляет собой другой контекст javascript. Почему бы вам не определить настраиваемый элемент в контексте iframe?   -  person Supersharp    schedule 17.02.2019
comment
@Supersharp, если я определяю настраиваемый элемент в контексте просмотра iframe, пользовательский элемент не будет работать в верхнем контексте просмотра.   -  person Raúl Arturo Chávez Sarmiento    schedule 18.02.2019


Ответы (3)


Если вы хотите имитировать импорт HTML, вам лучше использовать HTMLImports.min.js библиотеку, предоставленную в Репозиторий Github.

<script src="htmlimports.min.js"></script>

Обратите внимание, что встроенная поддержка HTML Imports в Chrome будет удалена в следующем выпуске (версия 73), поскольку не было достигнуто консенсуса с Mozilla и Apple по этой функции, предложенной Google ... но указанная выше библиотека по-прежнему будет работать как простой загрузчик HTML.


В качестве альтернативы вы можете загрузить содержимое HTML с помощью fetch(), как описано в этом сообщении об альтернативах импорта HTML.


Если вы по-прежнему хотите использовать элемент <iframe> для загрузки файла HTML, вам нужно подождать, пока файл будет загружен, прежде чем обращаться к его содержимому.

<iframe src="XA.html" onload="defineXA()"></iframe>

Я не думаю, что это хорошая практика, потому что это создаст бесполезный контекст просмотра.

person Supersharp    schedule 17.02.2019
comment
Хорошо, думаю, я пойду с этим подходом. Но прежде чем сделать это, я хотел бы понять, почему я не могу использовать класс, определенный в контексте просмотра iframe, для определения настраиваемого элемента в верхнем контексте просмотра. Кстати, я планировал удалить контекст просмотра iframe после того, как он сделает все, что нужно; это все еще влияет на производительность? - person Raúl Arturo Chávez Sarmiento; 18.02.2019
comment
@ RaúlArturoChávezSarmiento Потому что код Javascript может быть выполнен только в его контексте, но я думаю, вы нашли его сами - person Supersharp; 18.02.2019

После нескольких изменений скрипта для тестирования я понял, что HTMLElement отличается от top.HTMLElement. Вот почему наследование от HTMLElement не сработало для определения настраиваемого элемента, поскольку разрешено наследование от HTMLElement только из контекста просмотра, в котором этот настраиваемый элемент определен.

Затем измените сценарий на:

// iframe.js

class XAElement extends top.HTMLElement{
 constructor(){
  super()
  // Any customization here
 }
 // Any other methods for functionality
}
top.customElements.define('x-a', XAElement)

в итоге он работает.

Я пойду по этому пути, потому что после определения настраиваемого элемента и сохранения необходимого содержимого шаблона в классе конструктора (в качестве свойств можно выполнить до определения настраиваемого элемента) я могу удалить iframe. Таким образом, мне нужно загрузить только iframe; дождитесь выполнения этих требований; и удалите iframe, чтобы (я думаю) отменить влияние на производительность создания вложенного содержимого браузера.

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

Версия:

Я забыл проверить, что произойдет, если я удалю iframe в момент публикации ответа. Что происходит, так это то, что он перестает работать; поэтому я принимаю другой ответ.

person Raúl Arturo Chávez Sarmiento    schedule 18.02.2019

Честно говоря, я бы не стал загружать веб-компонент с помощью импорта HTML. Он устарел и будет удален из всех браузеров.

Вместо этого начните использовать модули ES6 или даже просто создайте традиционные файлы JavaScript.

Существует множество способов упаковать ваш шаблон в файл JS, включая инструменты для сборки компонентов или Webpack или другие вещи.

Мой совет - прекратить использовать мертвые технологии и перейти к текущим парадигмам загрузки модулей.

person Intervalia    schedule 21.02.2019