Это мой первый вопрос о SO. Так что, пожалуйста, будьте терпеливы со мной.
Я создаю очень маленькую веб-страницу с базовой структурой HTML.
<!DOCTYPE html>
<html lang = "en">
<head>
<title>BootVid</title>
<meta charset = "utf-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1">
<link rel = "shortcut icon" type = "image/png" href = "img/favicon.png" />
<link href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel = "stylesheet">
<script src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<link href = "https://vjs.zencdn.net/8.3.0/video-js.css" rel = "stylesheet" />
<script src = "https://vjs.zencdn.net/8.3.0/video.min.js"></script>
<style>
.fakeimg {
height: 200px;
background: #aaa;
}
</style>
</head>
<body>
<div class = "container mt-5">
<div id = "pageContent">
<!--Page Content Goes Here-->
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
routeTo("videoplayer");
});
function routeTo(path) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'components/' + path + '.html', true);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
if (this.status !== 200) return; // or whatever error handling you want
document.getElementById('pageContent').innerHTML = this.responseText;
};
xhr.send();
}
</script>
</body>
</html>
Таким образом, это в основном пустая веб-страница с div PAGE CONTENT, которую я загружаю HTML-кодом из отдельного файла .html в div pageContent на «главной» странице.
Базовая маршрутизация работает на 100% хорошо. Но когда я загружаю внешний html из одного из файлов .html, HTML отображается нормально, но код JavaScript никогда не выполняется. Как внедрить HTML-код в div вместе с кодом JavaScript, который должен выполняться при загрузке?
Вот пример страницы, которую мне нужно загрузить в div pageContent, который инициализирует экземпляр VideoJS.
<!--videoplayer.html-->
<div class = "container mt-5" id = "vidPlayer" hidden>
<div class = "mx-auto col-12 col-md-10 col-lg-8">
<video id = "my-video" class = "video-js vjs-fluid vjs-default-skin" controls preload = "none">
<source id = "video-source" src = ".mp4" type = "video/mp4"> <!--video/mp4 application/x-mpegURL-->
</video>
</div>
</div>
<script>
var player = videojs('my-video', {
repsonsive: true,
inactivityTimeout: 2000
});
</script>
Любая помощь будет принята с благодарностью.
Не могли бы вы привести пример того, как это будет достигнуто? Просто базовый пример. Приспособится к моему варианту использования. Спасибо за ваш ответ



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам нужно получить элементы скрипта из div pageContent, клонировать их и добавить в document.head. Вам просто нужно изменить функцию routeTo.
Ваша функция routeTo станет такой:
function routeTo(path) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'components/' + path + '.html', true);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
if (this.status !== 200) return; // or whatever error handling you want
document.getElementById('pageContent').innerHTML = this.responseText;
/* Loop For The Scripts Inside The pageCont DIV */
for (script of document.getElementById('pageContent').querySelectorAll('script')) {
var scriptElem = document.createElement('script');
if (script.src !== '' && typeof script.src !== 'undefined') {
scriptElem.src = script.src;
} else {
scriptElem.innerHTML = script.innerHTML;
}
/* Remove the old script from pageContent div */
script.parentNode.removeChild(script);
/* Check if scriptElem exists or not */
var scriptExists = (function() {
for (elem of document.querySelectorAll('script')) {
if (elem.outerHTML === scriptElem.outerHTML) return true;
}
return false;
})();
/* If script doesn't exists, append it to the head */
if (!scriptExists) {
document.head.appendChild(scriptElem);
}
}
};
xhr.send();
}
Это даже поддерживает внешние сценарии (т. е. сценарии с атрибутом src, установленным для другого файла JavaScript).
Теперь это предотвратит дублирование скрипта и удалит скрипт из div pageContent, как только скрипт будет добавлен к заголовку.
document.getElementById('pageContent').querySelectorAll('script')).forEach(script => { let scriptElem = document.createElement('script'); if (script.src !== '' && typeof script.src !== 'undefined') { scriptElem.src = script.src; } else { scriptElem.textContent = script.textContent; } document.head.appendChild(scriptElem); };@mplungjan, да, forEach был бы короче, но он устарел в Firefox 68 и удален с Firefox 71.
Ух ты! Большое спасибо
Так что после тестирования почти все работает. Единственное, что, я думаю, станет проблемой, это то, что скрипты не удаляются при просмотре нескольких страниц. Таким образом, это заканчивается несколькими копиями одного и того же сценария, пытающимися инициализировать один и тот же код. Любые идеи о том, как этого можно избежать?
@CodemasterUnited Вы не правы. ВЫ МОЖЕТЕ думать о for each, о котором я даже не слышал, пока вы не заставили меня посмотреть. Конструкция for each является расширением языка ECMAScript; он определен в спецификации E4X, которая широко не поддерживается. for (script of document.getElementById('pageContent').querySelectorAll('script')) очень неуклюжий
@WernerVenter, я отредактировал код, чтобы предотвратить дублирование скриптов, и теперь он также удаляет скрипты из div pageContent.
@CodemasterUnited Большое спасибо. Это отличное решение.
@WernerVenter, пожалуйста 😉😉
Попробуйте этот скрипт, который проверит, загружен ли JS.
Я не проверял это вживую. Я могу сделать это на днях, так как это интригует
const head = document.querySelector("head");
const scriptIsLoaded = (script, src) => {
const pageScripts = document.querySelectorAll('script');
if (src) {
// this may need some testing (pageScripts src = "jquery.js", script src = "https://....jQuery.js"
return pageScripts.find(pageScript => pageScript.src.endsWith(script));
}
return pageScripts.find(pageScript => pageScript.textContent.replace(/\s+/g, "") === script.textContent.replace(/\s+/g, "")); // compare text with all whitespace removed.
}
const routeTo = (path) => {
const url = `components/${path}.html`;
fetch(url)
.then((response) => response.text())
.then((html) => {
// Convert the HTML string into a document object
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
document.getElementById('pageContent').innerHTML = html; // load the page
// Get the script files
doc.querySelectorAll('script').forEach(script => {
const src = script.src;
if (src) {
if (scriptIsLoaded(src, true)) return; // already loaded
let scriptObject = document.createElement("script");
scriptObject.src = src;
head.appendChild(scriptObject)
} else {
const text = script.textContent;
if (text) {
if (scriptIsLoaded(scriptObject)) return; // textContent already in a script
let scriptObject = document.createElement("script");
scriptObject.textContent = scriptObject.textContent;
head.appendChild(scriptObject)
}
}
});
}).catch(function(err) {
// There was an error
console.warn('Something went wrong.', err);
});
};
Вы можете извлечь файл сценария и добавить его в заголовок текущего документа.