Выполнение JavaScript на импортированном HTML в Firefox

Я пытаюсь настроить динамический импорт 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, В предыдущем вопросе Stackru мне было предложено использовать это событие как способ узнать, когда импортированный документ успешно добавлен на страницу (ПРИМЕЧАНИЕ. При повторном рассмотрении этого вопроса я замечаю, что 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> элемент в заголовке документа, как показано на фотографии выше.

0 ответов

Другие вопросы по тегам