Я пытаюсь настроить динамический импорт HTML для работы в одностраничном веб-приложении.Я не использую какие-либо рамки для этого.Я могу добиться правильного поведения в Chrome.Тем не менее, я испытываю неправильное поведение в Firefox (и даже не начинаю с IE).
Я загружаю 2 полизаполнения: поликомпонент / загрузчик веб-компонентов , а также HTML-импорт полифилла в соответствии с указаниями предыдущего ответа на вопрос, который я написал.
После долгих проб и ошибок в Chrome мне удалось успешно импортировать целевой HTML-код в мой основной документ index.html
и получить встроенный JavaScript внутри импортированного документа для выполнения в DOM импортированного HTML в основном документе (в отличие от DOM импорта HTML).
Проблема возникает, когда я пытаюсь сделать то же самое в Firefox.Кажется, что встроенный JavaScript не выполняется в DOM основного документа.Вместо этого он действует на импортированных страницах DOM .
Вот код:
// index.html
...
<body>
// load the polyfills
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script src="src/scripts/helper/html-imports.min.js"></script>
<header> ... </header>
<nav> ... </nav>
<main>
/* Import Documents get appended to the <main> element */
</main>
// A Webpack-derived bundle including init.js
<script src="bundle-main.js"></script>
</body>
Логика JavaScript для приложения начинается с init.js
(частьпакет Webpack), который импортирует вспомогательную функцию, которая обрабатывает динамический импорт HTML.
// init.js
import {importHTML} from './helper/helper.js';
const APP_PATH = 'app.html';
const FORM_PATH = 'form.html';
(function(){
... some logic ...
importHTML(FORM_PATH);
})();
// helper.js
/**
* Dynamically imports HTML into the Main file
*
* @param {String} path The path to the document to import
* @return {null}
*/
export async function importHTML(path) {
let link = document.createElement('link');
link.rel = 'import';
link.href = path;
link.setAttribute('async', '');
link.onload = (e) => {
console.log('Success loading', e, e.target.href);
let importDoc = document.querySelector('link[rel="import"]').import;
let formHTML = importDoc.querySelector('#formContainer');
// get handle to <main> in document body
let target = document.body.querySelector('main');
target.appendChild(formHTML.cloneNode(true));
}
link.onerror = (e) => { console.error('Error loading', e, e.target.href); }
document.head.appendChild(link);
}
Импортированный документ, в данном случае form.html
, имеет HTML-разметку для формы, а затем выполняет сценарий JS внизустраницы.
// form.html
<section id="formContainer">
<style>
... embedded styles ...
</style>
<!-- load a compiled webpack bundle to handle with MDC SASS styles -->
<link rel="stylesheet" href="bundle-form.css">
<div id="splash">
<h1>App Title</h1>
<p>... desc ...</p>
<button type="button">Get Started</button>
</div>
<form action="" method="POST">
<ul>
<li>
<p class="form-question-desc">Select your gender:</p>
<div class="mdc-form-field question-container">
<label for="male">Male: </label>
<div class="mdc-radio">
<input class="mdc-radio__native-control" type="radio" name="gender" id="male" checked>
<div class="mdc-radio__background">
<div class="mdc-radio__outer-circle"></div>
<div class="mdc-radio__inner-circle"></div>
</div>
</div>
<label for="female">Female: </label>
<div class="mdc-radio">
<input class="mdc-radio__native-control" type="radio" name="gender" id="female">
<div class="mdc-radio__background">
<div class="mdc-radio__outer-circle"></div>
<div class="mdc-radio__inner-circle"></div>
</div>
</div>
</div>
</li>
<li>
<p class="form-question-desc">How old are you?</p>
<div class="text-field-container question-container" data-mdc-auto-init="MDCTextField">
<div class="mdc-text-field text-field mdc-text-field--upgraded">
<input type="number" id="age" name="age" class="mdc-text-field__input" value="33" required>
<label class="mdc-floating-label" for="age">Age: </label>
<div class="mdc-line-ripple" style="transform-origin: 31.5px center 0px;"></div>
</div>
</div>
</li>
<li>
... more markup using MDC classes/components ...
</li>
... other <li> elements ...
</ul>
<div id="submitForm">
<input type="submit" value="All Done!" class="app-theme button mdc-button mdc-button--raised" />
</div>
</form>
<div class="pagination">
<span id="pageBack" class="pagination-icon"><img src="icons/left-chevron.svg" alt="Arrow left"/></span>
<span id="pageForward" class="pagination-icon"><img src="icons/right-chevron.svg" alt="Arrow right"/></span>
</div>
<!-- execute script that handles form behavior -->
<script src="bundle-form.js" defer></script>
</section>
В bundle-form.js
у меня есть функция, которая прослушивает событие HTMLImportsLoaded
, прежде чем я начну манипулировать импортированным HTML DOM
.В предыдущем вопросе Stackoverflow мне было предложено использовать это событие как способ узнать, когда импортированный документ успешно добавлен на страницу (ПРИМЕЧАНИЕ. При повторном рассмотрении этого вопроса я замечаю, что HTMLImportsLoaded
прослушиватель событий находится в основном документе , index.html
, , а не в импортированном документе , как в моем текущем примере. Это может быть ключ.).
Посленастраивая различные инициализации элементов в form.js
, я вызываю setQuestionInitState
, который скрывает все, кроме первого вопроса о форме, а также скрывает элемент <form>
, показывая только заставку и кнопку для начала.
// form.js
let splashPage, form, formQuestions, submitBtn,
.. more variable declarations ...;
/**
* Sets initial state of form questions by
* hiding all but the first question
*
* @param {HTMLCollection} allQuestions A collection of LI elements
*/
let setQuestionInitState = (allQuestions) => {
let index = 0;
for (let question of allQuestions) {
if (index != 0) {
question.setAttribute('hidden', true);
}
index++;
}
}
/**
* Hide the splash page and display the form
* @return {[type]} [description]
*/
let startForm = () => {
splashPage.setAttribute('hidden', '');
form.removeAttribute('hidden');
}
window.addEventListener('HTMLImportsLoaded', function() {
// get reference to the form element in the main document
form = document.forms[0];
formQuestions = form.querySelector('ul').children;
// hide the form and the submit button
form.setAttribute('hidden','');
submitBtn.setAttribute('hidden', '');
splashPage = document.body.querySelector('#splash')
let splashBtn = document.body.querySelector('#splash > button')
splashBtn.addEventListener('click', startForm);
... more assignments and initializations ...
setQuestionInitState(formQuestions);
});
В Chrome эта последовательность успешно ждет, пока импорт HTML загрузит свою DOM в основной документ, а затем приступит к работе над этим DOM через JS в form.html
.Он успешно скрывает правильные вопросы и форму.
В Firefox, однако, он работает не так.Вместо этого он применяет логику JavaScript к импортированному документу (это может быть неправильной терминологией для этого «фрагмента документа» этого импорта).На DOM основного документа form.js
напрямую не влияет.Я вижу, что это касается виртуальной DOM, если я проверяю документ <head>
.
Возможно, дело в том, чтобы переместить мой HTMLImportsLoaded
в index.html
, но это идет вразрез с модульным подходом, который я пытаюсь сохранить (оставив свой JS для импортированного HTML внутри импортированного документа).Это также потребует еще более динамичного подхода к обработке импорта HTML и связанных с ним сценариев / css, вероятно, происходящего из некоторых умных сценариев в index.html
.
Я приветствую все идеи и заранее благодарю вас за любые советы, которые вымогу предложить.
Обновление
В соответствии с рекомендациями комментатора, я попытался переместить прослушиватель событий HTMLImportsLoaded
в импортирующий документ index.html
и загрузить сопутствующий скрипт для импортированный документ динамически:
//index.html
window.addEventListener('HTMLImportsLoaded', function() {
console.log('HTMLImportsLoaded loaded from main document');
let formJS = document.createElement('script');
formJS.src = 'bundle-form.js';
formJS.type = 'text/javascript';
if (document.body.appendChild(formJS)) {
console.log('Script was appended');
}
});
В chrome это работало нормально, однако в Firefox JavaScript не действует на DOM импортированного документа.Это, однако, похоже, влияет на DOM при проверке элемента <link>
внутри заголовка документа, как показано на фотографии выше.