在 Angular 自定义元素中传递外部属性或输入

问题描述

我试图在一个有角度的自定义元素标签中传递一个对象输入。自定义元素由 videojs 标签组成。元素未读取我在自定义元素标签中提供的输入。

这里的代码是我要转换为自定义元素的视频播放器组件。

import { Component,ElementRef,Input,On Destroy,OnInit,ViewChild,AfterViewInit,ViewEncapsulation } from '@angular/core';
import videojs from "video.js"

@Component({
  selector: 'app-video-player',templateUrl: './my-video-player.component.html',styleUrls: ['./my-video-player.component.scss'],encapsulation:ViewEncapsulation.Emulated
})
export class MyVideoPlayerComponent implements OnInit,OnDestroy,AfterViewInit {
  @ViewChild('myVideoPlayer',{static:true})
  myVideoPlayer:ElementRef


  @input() options:{
    fluid:boolean,aspectRatio:string,autoplay:boolean,controls:boolean,// height:number,// width:number,sources:{
      src:string,type:string
    }[],}

  player:videojs.Player;

  constructor(
  ) { }

  ngAfterViewInit(){
  }
  
  ngOnInit() {
    this.player = videojs(this.myVideoPlayer.nativeElement,this.options,function onPlayerReady() {
      console.log('onPlayerReady',this);
    });    
  }

  ngOnDestroy() {
    
  }

}


这是视频播放器组件的 HTML


<video id="video-js" preload="none" class="video-js vjs-default-skin" controls #myVideoPlayer></video>


这是我将 MyVideoPlayerComponent 转换为自定义元素的 appModule 代码

import { browserModule } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA,dobootstrap,Injector,NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MyVideoPlayerComponent } from './my-video-player/my-video-player.component';
import { createCustomElement } from '@angular/elements';

@NgModule({
  declarations: [
    MyVideoPlayerComponent
  ],imports: [
    browserModule,AppRoutingModule,],providers: [],schemas:[CUSTOM_ELEMENTS_SCHEMA],bootstrap: [AppComponent],entryComponents:[MyVideoPlayerComponent]
})

export class AppModule implements dobootstrap {
  constructor(private injector:Injector){

    const webComponent=createCustomElement(MyVideoPlayerComponent,{injector:this.injector});
    
    customElements.define('custom-player',webComponent)

  }

  

  ngdobootstrap(){}
 }


在构建项目之后,或者即使我直接使用我在同一个 Angular 项目中制作的内部测试组件。它显示视频播放器组件但不播放视频,因为即使我提供属性,它也无法读取源。

下面显示代码显示了我如何尝试将输入提供给自定义元素。

<custom-player options="{ autoplay: true,controls: true,sources: [{ src: '../../assets/video.mp4',type: 'video/mp4' }]}" ></custom-player>


如果你研究这个问题会很棒。

这是我声明的自定义元素的给定屏幕截图。

红色标记表明它正在拾取 src,而突出显示标记表明它没有将 src 放入视频标签中。

enter image description here

解决方法

从资产开始时您不应该需要 ../../(这通常是从配置开始的有效起点)。

此外,您想将 <custom-player options= 更改为 <custom-player [options]=(没有 [],您实际上传入的是字符串,而不是对象)。

我想您遵循了一些教程,例如 this。如果以上没有影响,请尝试与该示例进行比较,看看是否存在其他相关差异。

编辑:
关于属性绑定的一个非常简单的例子:

// interface for options

export interface VideoOptions {
  fluid?: boolean;
  aspectRation?: string;
  autoplay?: boolean;
  controls?: boolean;
  sources?: Sources[];
}

export interface Source {
  src: string;
  type: string;
}

// ParentComponent ts

export class ParentComponent {
  options: VideoOptions = {
    autoplay: true,controls: true,sources: [{ src: 'assets/video.mp4',type: 'video/mp4' }]
  }
}

// ParentComponent html

<app-child-component [options]="options">
</app-child-component>

// ChildComponent ts
export class ChildComponent {
  @Input() options: VideoOptions;
}

// ChildComponent html
<div>
  {{options?.fluid}} <br>
  {{options?.aspectRatio}} <br>
  {{options?.controls}} <br>
  {{options?.autoplay}} <br>
  <ng-container *ngIf="options.sources">
    <div *ngFor="let source of options.sources">
      {{source.src}} --- {{source.type}}
    </div>
  </ng-container>
</div>
,

看起来您已经从您的评论中解决了这个问题,但只是为了让其他最终遇到同样问题的人清楚,这就是发生这种情况的原因。

当您将组件转换为 Angular Web 组件时,任何输入都将按此处所述进行映射:

https://angular.io/guide/elements#mapping

自定义元素承载 Angular 组件,在组件中定义的数据和逻辑与标准 DOM API 之间提供桥梁。组件属性和逻辑直接映射到 HTML 属性和浏览器的事件系统。

创建 API 解析组件以查找输入属性,并为自定义元素定义相应的属性。它转换属性名称以使其与不区分大小写的自定义元素兼容。结果属性名称使用破折号分隔的小写字母。例如,对于带有@Input('myInputProp') inputProp 的组件,对应的自定义元素定义了一个属性 my-input-prop。

自定义元素只是承载 Angular,它本身不是 Angular 组件。要将数据传递给输入,您必须使用 Angular 在该元素上创建的属性,类似于您使用数据属性的方式。属性值是一个字符串,所以如果你想传入一个对象,你必须把它和JSON进行转换。