Привязка видео YouTube к элементу Div из отдельного файла JS
У меня есть проблема при встраивании видео YouTube в одностраничное мобильное приложение PhoneJS. В PhoneJS сценарии JS определены в другом файле. Итак, я определил HTML-div следующим образом:
<div id="player"></div>
Теперь в файле JS я сделал это:
function getVideo() {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player(playerDiv, {
height: '250',
width: '444',
videoId: sIFYPQjYhv8
});
}
}
Когда я запускаю и просматриваю отладчик, выполняется звонок на Youtube, и ответ получен, но он не отображается в представлении.
Хорошо, так как я использую привязку KnockoutJS, я изменил div в представлении html следующим образом:
<iframe id="player" type="text/html" width="444" height="250" frameborder="0" data-bind="attr: { src: src }"></iframe>
А затем передайте идентификатор видео src следующим образом:
src: ko.observable('http://www.youtube.com/embed/' + sIFYPQjYhv8 + '?autoplay=1')
В этом случае, однако, в отладчике вызов даже не делается на Youtube. Ничего просто не происходит. На самом деле я предпочитаю использовать вызов API вместо второго подхода.
Любые предложения о том, как заставить первый подход работать? Я имею в виду использование вызова API?
РЕДАКТИРОВАТЬ Просто хочу отметить, что когда я добавляю код ниже в представление, видео транслируется в порядке.
<h1>Video</h1>
<div id="player"></div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player(playerDiv, {
height: '250',
width: '444',
videoId: 'sIFYPQjYhv8'
});
}
</script>
1 ответ
Я думаю, что самый простой способ сделать это - использовать собственный обработчик привязки с флагом, установленным из обратного вызова onYouTubeIFrameAPIReady
ko.bindingHandlers['player'] = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Check if global script and function is declared.
if ( !document.getElementById('playerScript') ) {
// Create script
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Create global function that their API calls back
window.playerReady = ko.observable(false);
window.onYouTubeIframeAPIReady = function() {
window.playerReady(true);
};
}
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
id = value.id(),
height = ko.unwrap(value.height) || '250',
width = ko.unwrap(value.width) || '444'
;
if ( !value.id()) {
return;
}
if ( !window.playerReady() ) {
// YT hasn't invoked global callback. Subscribe to update
var subscription;
subscription = window.playerReady.subscribe( function(newValue) {
if ( newValue ) {
subscription.dispose();
// Just get this binding to fire again
value.id.notifySubscribers(value.id());
}
});
} else {
var player = new YT.Player( element, {
height: height,
width: width,
videoId: id
});
}
},
}
Теперь измените ваш игрок div на
<div data-bind="player: { id: id, height: height, width: width }"></div>
Наконец, связать
var vm = {
id: 'sIFYPQjYhv8',
height: '250',
width: '444'
};
ko.applyBindings( vm )
РЕДАКТИРОВАТЬ
Чтобы убрать зависимость от окна, поместите тег script, который добавляет новый элемент script, обратно, настройте, как показано ниже, измените их обратный вызов и используйте setTimeout вместо наблюдаемого "playerReady"
HTML-скрипт
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.setAttribute('id', 'playerScript');
tag.setAttribute('data-ready', 'false');
...
function onYouTubeIframeAPIReady = function() {
document.getElementById('playerScript').setAttribute('data-ready', 'true');
};
Связывание игрока
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
id = value.id(),
height = ko.unwrap(value.height) || '250',
width = ko.unwrap(value.width) || '444',
playerScript = document.getElementById('playerScript')
;
if ( !value.id()) {
return;
}
if ( !playerScript || playerScript.getAttribute('data-ready') !== 'true' ) ) {
// YT hasn't invoked global callback.
setTimeout( function() {
value.id.notifySubscribers(value.id());
}, 50);
} else {
var player = new YT.Player( element, {
height: height,
width: width,
videoId: id
});
}
}