<iframe>
& <video>
Автоигра
Автоигра уже не та, что раньше.Слишком много ограничений и различных критериев , связанных с получением тега <video>
для автоигры.Вот что нужно было:
<video>
атрибуты тега [muted]
и [autoplay]
атрибуты
<video ... muted autoplay></video>
<iframe>
атрибут тега [allow="autoplay"]
.Полный экран не является обязательным
<iframe ... allowfullscreen allow="autoplay; fullscreen"></iframe>
В демонстрационном примере ниже loadVideo()
- это функция, которая загружает файл MP4 в <video>
тег [src]
в соответствии с текущим временем.Автозагрузка носителей из <iframe>
сложна, потому что они являются одним из последних загружаемых материалов DOM.Лучше всего запускать функцию с дочерней страницы (videoframe.html
) в IIFE (выражении немедленного вызова функции) .
(function() {
loadVideo();
})();
Обещания
Чтобы вызвать метод play()
, вам нужно использовать Promise API .Это еще один случай, когда что-то работает, и инженеры хотят его переосмыслить .
async function promisePlay() {
try {
await document.querySelector('video').play();
} catch (err) {
...
}
}
postMessage
Для междоменной связи с использованием postMessage API через <iframe>
разработчик должен владеть обоими доменами.Право собственности не обязательно означает полные права администратора, достаточно того, чтобы обе страницы действительно могли быть отредактированы.Есть несколько API, которые встретят вас на полпути, например, YouTube и Vimeo.
Обычно родительская страница (index.html
) отправит сообщение:
window.frames[0].postMessage(data, origin);
window.frames[0]
получит первый <iframe>
и получит доступ к содержимому окна, что эквивалентнодо: document.querySelector('iframe').contentWindow;
. data
это просто строка. origin
- это обычно location.protocol
и location.hostname
или location.origin
родительской страницы (index.html
): https://www.example.com
.
Дочерняя страница (videoframe.html
) получает data
(просто типичная строка), прослушивая событие message
для своего объекта Window :
window.addEventListener("message", callback);
Mostпримеры показывают, как сообщение отправляется и принимается, и результат отображения сообщения на дочерней странице - lame ?.Вот как бы выглядел обратный вызов, если бы он был действительно полезен:
function callback(event) {
var string = event.data;
// Optional-------------------------
var from = event.origin;
if (from !== 'https://www.example.com') {
document.querySelector('#displayMsg').textContent = `MESSAGE REJECTED`;
return;
}
//----------------------------------
if (string === "play") {
promisePlay();
} else if (string === "pause") {
document.querySelector('video').pause();
} else if (string === "stop") {
document.querySelector('video').pause();
document.querySelector('video').currentTime = 0;
} else {
document.querySelector('#displayMsg').textContent = `ERROR: ${string} is not a command.`;
}
}
Демо
index.html
Примечание: Следующий фрагмент кода не работает должным образом из-за ограничения SO при использовании <iframe>
.Для полнофункциональной демонстрации перейдите на этот Plunker .
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
font: 400 16px/1.5 Consolas;
overflow: hidden;
}
main {
width: 100%;
height: auto;
padding: 10px;
}
section {
height: 0;
width: 100%;
position: relative;
padding-bottom: 56.25%;
margin: 15px auto 5px;
}
fieldset {
width: fit-content;
padding: 5px;
}
iframe {
height: 100%;
width: 100%;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
select,
button {
font: inherit;
padding: 0 3px;
line-height: 1.2;
}
#msg {
position: absolute;
z-index: 1;
background: rgba(0, 0, 0, 0.5);
}
#time,
#rX {
display: block;
float: left;
color: gold;
padding: 0 5px;
width: 70px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Frame</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<section>
<iframe src="https://run.plnkr.co/preview/cjpwrvczh00073a5v3m08unmw/videoframe.html" width='100%' height='100%' scrolling='no' frameborder='0' allowfullscreen allow="autoplay; fullscreen"></iframe>
</section>
<form id='control'>
<fieldset>
<select id='tX'>
<option value='Timeslot'>Select</option>
<optgroup label='Command'>
<option>Play</option>
<option>Pause</option>
<option>Stop</option>
</optgroup>
<optgroup label='Load Media'>
<option>Video 1</option>
<option>Video 2</option>
<option>Video 3</option>
</optgroup>
<optgroup label="Test">
<option>Messages</option>
<option>Controls</option>
</optgroup>
</select>
<button>Send</button>
</fieldset>
</form>
</main>
<script>
window.onload = function(e) {
var ctrl = document.forms.control;
var cX = ctrl.elements;
var tX = cX.tX;
ctrl.addEventListener('submit', function(e) {
e.preventDefault();
window.frames[0].postMessage(tX.value, "https://" + location.hostname);
console.log(tX.value);
});
};
</script>
</body>
</html>
videoframe.html
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
font: 400 16px/1.5 Consolas;
overflow: hidden;
}
main {
width: 100%;
height: auto;
padding: 10px;
}
section {
height: 0;
width: 100%;
position: relative;
padding-bottom: 56.25%;
margin: 15px auto 5px;
}
fieldset {
width: fit-content;
padding: 5px;
}
iframe {
height: 100%;
width: 100%;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
select,
button {
font: inherit;
padding: 0 3px;
line-height: 1.2;
}
#msg {
position: absolute;
z-index: 1;
background: rgba(0, 0, 0, 0.5);
}
#time,
#rX {
display: block;
float: left;
color: gold;
padding: 0 5px;
width: 70px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Video iframe</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<aside id='msg'>
<output id='rX'></output>
<time id='time'></time>
</aside>
<video id='vX' src='about:blank' width='96%' muted autoplay></video>
<script>
var v = document.getElementById('vX');
var vid =
'https://storage04.dropshots.com/photos6000/photos/1381926/20170326/';
var r = document.getElementById('rX');
var t = document.getElementById('time');
(function() {
loadVideo();
})();
window.addEventListener("message", rXMsg);
function rXMsg(e) {
var msg = e.data;
switch (msg) {
case 'Play':
playMedia();
break;
case 'Pause':
v.pause();
break;
case 'Stop':
v.pause();
v.currentTime = 0;
break;
case 'Video 1':
v.src = vid + '005609.mp4';
v.load();
break;
case 'Video 2':
v.src = vid + '005610.mp4';
v.load();
break;
case 'Video 3':
v.src = vid + '005612.mp4';
v.load();
break;
case 'Messages':
toggleAttr('#msg', 'hidden');
break;
case 'Controls':
toggleAttr('#vX', 'controls');
break;
default:
loadVideo();
break;
}
stamp(msg);
}
function loadVideo() {
var hrs = stamp();
// 05:00 - 09:59
if (hrs >= 5 && hrs < 10) {
v.src = vid + '005609.mp4';
v.load();
}
// 10:00 - 21:59
else if (hrs >= 10 && hrs < 22) {
v.src = vid + '005610.mp4';
v.load();
}
// 22:00 - 04:59
else {
v.src = vid + '005612.mp4';
v.load();
}
stamp('Autoload');
}
async function playMedia() {
try {
await v.play();
} catch (err) {
stamp('Promise Rejected');
}
}
function toggleAttr(selector, attr) {
var node = document.querySelector(selector);
var prop = node.getAttribute(attr);
if (!prop) {
node.setAttribute(attr, true);
} else {
node.removeAttribute(attr);
}
}
function stamp(str) {
var now = new Date();
var hrs = now.getHours();
var min = now.getMinutes();
var sec = now.getSeconds();
var h = hrs > 9 ? "" + hrs : "0" + hrs;
var m = min > 9 ? "" + min : "0" + min;
var s = sec > 9 ? "" + sec : "0" + sec;
var time = h + ":" + m + ":" + s;
r.textContent = str;
t.textContent = time;
return hrs;
}
</script>
</body>