如何让@vimeo/player 参与我的 Angular2/Typescript 项目?

How do I get @vimeo/player to work on my Angular2/Typescript project?

问题:

如何让 @vimeo/player 处理我的 Angular2/Typescript 项目(特别是 Ionic2)?

描述:

正在尝试让 vimeo player 与 Angular2/Typescript 一起工作。

npm install --save @vimeo/player

根据他们的文档,可以像这样使用库:

If you’re using a module bundler like webpack or rollup, the exported object will be the Player constructor (unlike the browser where it is attached to window.Vimeo):

import Player from '@vimeo/player';

const player = new Player('handstick', {
    id: 19231868,
    width: 640
});

player.on('play', function() {
    console.log('played the video!');
});

看起来超级有前途!但是没用。

我尝试过的:

我已经安装了 @vimeo/player and @types/vimeo__player 我在我的 Ionic2 应用程序中创建了一个播放器组件。

player.ts:

import {Component, ViewChild} from '@angular/core';
import {NavController} from "ionic-angular/index";

//noinspection TypeScriptCheckImport,TypeScriptCheckImport
import Player from "@vimeo/player";


@Component({
  selector: 'player-component',
  templateUrl: 'player.html'
})
export class PlayerComponent {

  @ViewChild('player_container') playerContainer;
  private player: Player;

  constructor(public navCtrl: NavController){}

  ngAfterViewInit() {
    // child is set
    this.player = new Player(this.playerContainer);
    console.log(Player);
  }

}

我使用视图子项,但我也尝试使用元素的 ID。

player.html

<div #player_container></div>

并得到以下错误:

Uncaught (in promise): TypeError: You must pass either a valid element or a valid id. Player@http://localhost:8100/build/main.js:102846:32 ngAfterViewInit@http://localhost:8100/build/main.js:74715:80 callProviderLifecycles@http://localhost:8100/build/main.js:11417:33 callElementProvidersLifecycles@http://localhost:8100/build/main.js:11392:35 callLifecycleHooksChildrenFirst@http://localhost:8100/build/main.js:11376:47 checkAndUpdateView@http://localhost:8100/build/main.js:12408:36 callWithDebugContext@http://localhost:8100/build/main.js:13462:47 detectChanges@http://localhost:8100/build/main.js:10474:81 _viewAttachToDOM@http://localhost:8100/build/main.js:43884:53 _transition@http://localhost:8100/build/main.js:43976:34 onInvoke@http://localhost:8100/build/main.js:4406:43 run@http://localhost:8100/build/polyfills.js:3:4146 http://localhost:8100/build/polyfills.js:3:13734 onInvokeTask@http://localhost:8100/build/main.js:4397:47 runTask@http://localhost:8100/build/polyfills.js:3:4841 o@http://localhost:8100/build/polyfills.js:3:1898 invoke@http://localhost:8100/build/polyfills.js:3:10674

如您所见,它可以编译但在运行时崩溃。

@types/vimeo__player 好像还没有完成,导入的时候好像都没注意到@vimeo/player

issue on github regarding vimeo__player 似乎表明这是真的。

It looks like module resolution is correctly resolving it as a JS module, but only because it didn't find the types first. Are you sure you've correctly included those types? --listFiles would show you if it's lincluded.

额外内容:

Issued opened on Vimeo's github player page.

您的问题不是由 @types/vimeo__player 引起的,也不与您的构建有关 system/configuration。

TypeScript 类型定义从不,从不从不 影响运行时的行为。即使编译时错误除了在控制台中显示红色之外没有其他影响,JavaScript 仍会发出。

看看你得到的堆栈跟踪,我们也可以说 Player 是有效导入的,因为你说没有编译时错误,构建时一切都很好事物的方面。

事实上,错误说明了一切:TypeError: You must pass either a valid element or a valid id..

Player 表示它期望 HTMLElement.

问题是,您正在使用 Angular 中的 @ViewChild()。当您查询本机元素时,此装饰器将 return 包装器。此包装器的类型为 ElementRef,并且有一个名为 nativeElement 的 属性,其中包含原始的 DOM 元素。

所以不要这样做:

this.player = new Player(this.playerContainer);

这样做:

this.player = new Player(this.playerContainer.nativeElement);

但你现在可能会想 "why TypeScript didn't produced a type error since I'm not passing a native element ?"。这是一个很好的问题,我没有足够的数据来确定,但我认为你的导入可能不正确。

而不是:

//noinspection TypeScriptCheckImport,TypeScriptCheckImport
import Player from "@vimeo/player";

你能试试看吗?

import { Player } from '@vimeo/player';

查看 .d.ts 文件,Player 似乎是一个命名导出。但你是对的,@vimeo/player 的类型定义不完整,或者与 JavaScript 库不同步。你应该知道 TypeScript 中的这类问题,尽管这不是每天都会发生 ;)

对于标准 项目,此导入语句有效。

import * as Player from "@vimeo/player/dist/player.js";

如果您的 ViewChild 未定义(由于延迟加载等),您可以尝试这样做:

  • ViewChildren 代替 ViewChild;
  • 等待 DOM 可用,然后 运行 您的代码;

代码:

import { Component, ViewChildren } from '@angular/core';
import Player from "@vimeo/player";


@Component({
  selector: 'player-component',
  templateUrl: 'player.html'
})
export class PlayerComponent {

  private player: Player;
  @ViewChildren('player_container') playerContainer;

  ngAfterViewInit() {
    /* wait DOM be available */
    this.playerContainer.changes.subscribe(item => {
        if (this.playerContainer.length) {
            /* DOM AVAILABLE */
            this.player = new Player(this.playerContainer.first.nativeElement);

            this.player.on('play', function() {
                console.log('played the video!');
            });

            this.player.getVideoTitle().then(function(title) {
                console.log('title:', title);
            });
        }
    })
  }
}

根据他们的文档

When the library loads, it will scan your page for elements with Vimeo attributes. Each element must have at least a data-vimeo-id or data-vimeo-url attribute in order for the embed to be created automatically.

所以基本上它需要一个 div 标签,其中包含“data-vimeo-id”属性或“data-video-url”属性,并在调用播放器的构造函数之前分配了有效值。

所以你可以使用属性绑定分配视频id(到data-vimeo-id)或视频url(到data-video-url) 添加到模板文件中的 div 标签。

<div [attr.data-vimeo-id]="videoId"> </div>

并将要嵌入的视频的视频 ID 分配给 Typescript 文件(在 ngOninit 中)中的变量“videoId”。 同样可以用 url 在这种情况下 [attr.data-vimeo-url]="videoUrl";