gpt4 book ai didi

angular - onYouTubeIframeAPIReady 未在 angular2 网络应用程序上触发

转载 作者:太空狗 更新时间:2023-10-29 18:16:14 28 4
gpt4 key购买 nike

我正在使用 angular 2、typescript 和 YouTube API 构建一个网络应用程序,以便在用户登录后向页面添加播放器。

因此,一旦登录,应用程序就会加载以下组件:

export class MyComponent implements OnInit {
myService: MyService;

constructor( private _myService: MyService ) {
this.myService = _myService;
}

ngOnInit() {
this._myService.loadAPI();
}

}

组件 html 包含以下标记:

<iframe id="player" type="text/html" width="640" height="360"
src="http://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1"
frameborder="0" allowfullscreen></iframe>

最后,该服务具有以下内容:

  player: YT.Player;

loadAPI(){
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
console.log('API loaded'); // this is shown on the console.
}

onYouTubeIframeAPIReady(){
this.player = new YT.Player('player', {
events: {
'onReady': this.onPlayerReady,
'onStateChange': this.onPlayerStateChange
}
});
console.log('youtube iframe api ready!'); // this is never triggered.
}

onPlayerReady(event){
event.target.playVideo();
}

onPlayerStateChange(status){
console.log(status.data);
}

我读到 API 会自动调用函数“onYouTubeIframeAPIReady”,所以我想知道我应该做些什么不同的事情才能让它正常工作。

最佳答案

您需要在全局对象上定义函数 onYouTubeIframeAPIReady。这与 JavaScript 的链接答案中的工作方式完全相同。接下来是这里所有 100% 的 JavaScript 内容,通过其 JavaScript 性质的超集适用于 TypeScript。

如果您使用的是模块(通常是 Angular 2 应用程序的情况),那么您的代码是隔离的,默认情况下不会在全局范围内执行。这意味着为了定义全局,我们需要获得对全局对象的引用。在浏览器中,这非常简单,因为 window 指的是全局(除非它被隐藏)。

您需要编写的内容非常简单。本质上是

window.onYouTubeIframeAPIReady = function () { ... };

这意味着采用您当前的代码,如下所示

export default class YouTubeService {
...
loadAPI() {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
console.log('API loaded'); // this is shown on the console.
}

onYouTubeIframeAPIReady() { }
}

然后改成这个

export default class YouTubeService {
...
loadAPI() {
window.onYouTubeIframeAPIReady = function () { };

var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
console.log('API loaded'); // this is shown on the console.
}
}

您将收到一个 TypeScript 错误,告诉您 window 没有为 onYouTubeIframeAPIReady 定义。这很容易通过多种方式解决,但我将仅说明两种可能性,两种可能性都可以,技术上两者都不是必需的,因为尽管有错误,TypeScript 仍会发出代码。

  1. 在抑制错误的窗口上指定类型断言

    (window as any).onYouTubeIframeAPIReady = function () {}
  2. 在 window 上声明成员,以便您可以无错地分配给它。在模块内部(回想一下我们不在全局范围内)我们可以使用以下形式

    declare global {
    interface Window {
    onYouTubeIframeAPIReady?: () => void;
    }
    }

请记住,所有 JavaScript 都是有效的 TypeScript,并且 TypeScript 不会向 JavaScript 添加行为或功能。它是 JavaScript 的类型化 View (如果您愿意的话)的一种解释,允许对其进行静态验证并具有出色的工具,以捕获错误,提供高效的编辑体验,并允许在代码级别记录期望。

这只是 JavaScript。它与 Youtube iframe api not triggering onYouTubeIframeAPIReady 中使用的解决方案完全相同,我发布它只是因为似乎存在脱节。


附录: 值得注意的是,如果您使用 SystemJS 或 RequireJS 等模块加载器,您可以通过加载器配置抽象手动脚本标记注入(inject)过程。这样做的好处是更清晰、更具声明性的代码以及更高的可测试性,因为您可以 stub YouTube 依赖项,从而将您的测试与网络隔离开来。

对于 SystemJS,您将使用以下配置

SystemJS.config({
map: {
"youtube": "https://www.youtube.com/iframe_api"
},
meta: {
"https://www.youtube.com/iframe_api": {
"format": "global",
"scriptLoad": true,
"build": false
}
}
});

你可以写

export default class YouTubeService {
async loadAPI() {
window.onYouTubeIframeAPIReady = function () {
console.log('API loaded'); // this is shown on the console.
};
try {
await import('youtube'); // automatically injects a script tag
}
catch (e) {
console.error('The YouTube API failed to load');
}
}
}

declare global {
interface Window {
onYouTubeIframeAPIReady?: () => void;
}
}

现在,如果您想测试这段代码,模拟 YouTube API,您可以编写

测试/测试 stub /stub-youtube-api.ts

(function () {
window.onYouTubeIframeAPIReady();
}());

测试/服务/youtube-service.spec.ts

import test from 'blue-tape';

import YouTubeService from 'src/services/youtube.service'

SystemJS.config({
map: {
"youtube": "test/test-stubs/stub-youtube-api.ts"
}
});

if(typeof window === 'undefined') {
global.window = {};
}


test('Service must define a callback for onYouTubeIframeAPIReady', async ({isNot}) => {
const service = new YouTubeService();
await service.loadAPI();
t.isNot(undefined, window.onYouTubeIframeAPIReady);
});

关于angular - onYouTubeIframeAPIReady 未在 angular2 网络应用程序上触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42868225/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com