在尝试使用 Windows 8 Metro js 应用程序(使用 HTML/Javascript/CSS 创建的应用程序,意在在即将推出的 Windows 8 的 Windows 应用商店中发布的应用程序)的功能时,我创建了一个非常简单的测试应用程序,它可以创建动态的基于 iframe 的 YouTube 播放器,与特定视频相关联。到目前为止,一切都很好。
后来,我希望能够从在该 iframe 上播放的视频中获得反馈。Google 为实现这一点提供了广泛的帮助,并解释说您需要动态创建一个指向 YouTube iframe API 的标签,然后,一旦完成加载,它将自动在您的代码中调用“onYouTubeIframeAPIReady()”函数,因此它知道 API 已准备好与您最近创建的播放器一起操作,方法是调用操纵播放器的函数,以及返回统计信息以外的其他函数,甚至附加监视播放器状态的事件处理程序。很容易,对吧?
不幸的是,Windows 8 Metro js 应用程序并非如此。
事实证明,由于应用程序运行在所谓的“本地上下文”中,与“Web 上下文”不同,您实际上无法为这些应用程序在 Web 上插入指向远程资源的 <script> 标签。这意味着,我永远无法访问 YouTube iframe API 来处理我的播放器。
现在,检查 < script > 标记中引用的代码,我意识到,截至今天,有 2 个相关的 .js 文件,一个实际上试图启动另一个,而那个(显然)是自包含的。看到这一点,我抓起两个 .js 文件的副本,将它们存储到我的项目中,进行所有更改,以便项目在本地引用它们,而不是远程引用它们,瞧!现在,我从 iframe YouTube 播放器获得了功能齐全的反馈!
然而,尽管成功了,我还是忍不住认为我在这里作弊。我正在保存我不应该控制的两个 .js 文件的副本。所有这一切感觉就像一个,嗯,“肮脏的黑客”,只是为了让事情在我的应用程序中工作。
所以,知道这一点,我问你:有没有其他方法可以查询和控制嵌入到我的 Windows 8 Metro js 应用程序中的基于 iframe 的 YouTube 播放器,我知道由于“本地上下文”限制,我只是无法从 Google 引用 iframe API?
此外,基于 iframe 的播放器很可能不是我打算实现的真正解决方案(即能够从播放器获得及时的反馈)。如果是这样,你还有什么推荐的?我对这里的大多数建议持开放态度。
如果你有兴趣,这些是我的测试应用程序的“default.html”和“default.js”,所以你可以看到我在说什么:
默认.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>PruebaYouTube</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- PruebaYouTube references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
</head>
<body>
<p id="contentGoesHere">Content goes here</p>
<div id="playerPlaceholder"></div>
<button id="createPlayer" style="display: none">Create Player</button>
</body>
</html>
default.js:(yt_iframe_api.js和yt_widgetapi.js是我的 YouTube API 文件副本)
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
var currentPlayer,
embeddedText;
function initApp() {
var ytScript = document.createElement('script');
ytScript.src = "/js/yt_iframe_api.js";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(ytScript, firstScriptTag);
}
function onYouTubeIframeAPIReady() {
var createPlayerButton = document.getElementById("createPlayer");
createPlayerButton.style.display = "";
}
function onPlayerReady(event) {
while (embeddedText.firstChild) {
embeddedText.removeChild(embeddedText.firstChild);
}
embeddedText.appendChild(document.createTextNode("Listo!"));
}
function onPlayerStateChange(event) {
while (embeddedText.firstChild) {
embeddedText.removeChild(embeddedText.firstChild);
}
embeddedText.appendChild(document.createTextNode("Estado: " + event.data));
}
function createYouTubePlayer(mouseEvent) {
var playerPlaceholder = document.getElementById("playerPlaceholder");
while (playerPlaceholder.firstChild) {
playerPlaceholder.removeChild(playerPlaceholder.firstChild);
}
var playerFrame = document.createElement("iframe");
playerFrame.id = "playerFrame";
playerFrame.setAttribute("type", "text/html");
playerFrame.style.position = "absolute";
playerFrame.style.top = "100px";
playerFrame.style.left = "100px";
playerFrame.width = "640px";
playerFrame.height = "390px";
playerFrame.src = "http://www.youtube.com/embed/u1zgFlCw8Aw?controls=0&autoplay=1";
playerFrame.frameBorder = "0";
playerPlaceholder.appendChild(playerFrame);
embeddedText = document.createElement("p");
embeddedText.style.fontSize = "24px";
embeddedText.style.position = "absolute";
embeddedText.style.top = "150px";
embeddedText.style.left = "150px";
playerPlaceholder.appendChild(embeddedText);
currentPlayer = new YT.Player('playerFrame', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function attachAllEvents() {
var createPlayerButton = document.getElementById("createPlayer");
createPlayerButton.addEventListener("click", createYouTubePlayer, false);
}
(function () {
"use strict";
WinJS.Binding.optimizeBindingReferences = true;
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
initApp();
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll().done(attachAllEvents));
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
})();