如何在此 Angular 16 电影应用程序中显示 YouTube 视频轮播?

问题描述 投票:0回答:2

我一直在使用 Angular 16、TypeScript 和电影数据库 (TMDB) 开发 SPA。

我在 Bootstrap 5 轮播中显示电影预告片时遇到问题。

app\services\movie-service.service.ts
我有:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';
import { HttpClient } from '@angular/common/http';
import { MovieResponse, Movie } from '../models/Movie'; 
import { Trailer, TrailerResponse } from '../models/Trailer';

@Injectable({
  providedIn: 'root'
})

export class MovieService {

  constructor(private http: HttpClient) { }

  public getMovieTrailers(id: Number): Observable<TrailerResponse>{
    return this.http.get<TrailerResponse>(`${environment.apiUrl}/movie/${id}/videos?api_key=${environment.apiKey}`);
  }

  public getMovieDetails(id: Number): Observable<Movie>{
    return this.http.get<Movie>(`${environment.apiUrl}/movie/${id}?api_key=${environment.apiKey}`);
  }
}

app\models\Trailer.ts
我有:

export interface Trailer {
    id?: string;
    key?: string;
    name?: string;
    site?: string;
}

export interface TrailerResponse {
    results?: Trailer[];
}   

我使用以下 ts 文件创建了一个 TrailerCarouselComponent 组件:

import { Component, Input } from '@angular/core';
import { Trailer } from '../../models/Trailer';

@Component({
  selector: 'app-trailer-carousel',
  templateUrl: './trailer-carousel.component.html',
  styleUrls: ['./trailer-carousel.component.scss']
})
export class TrailerCarouselComponent {
  @Input() trailers!: Trailer[];
}

这个模板:

<div id="trailersCarousel" class="carousel slide" data-bs-interval="false">
  <ol *ngIf="trailers.length > 1" class="carousel-indicators">
    <li
      *ngFor="let video of trailers; let i = index"
      data-bs-target="#trailersCarousel"
      attr.data-slide-to="{{ i }}"
      class="{{ i === 0 ? 'active' : '' }}"
    >
      {{ i + 1 }}
    </li>
  </ol>

  <div class="carousel-inner">
    <div
      *ngFor="let video of trailers; let i = index"
      
      class="carousel-item"
      [ngClass]="{ 'active': i === 0 }"
    >
      <iframe
        class="embed-responsive-item"
        src="https://www.youtube.com/embed/{{ video.key }}"
      ></iframe>
    </div>
  </div>
</div>

我在 MovieDetailsComponent 组件中使用上述组件:

import { Component, Input } from '@angular/core';
import { Movie } from '../../models/Movie';
import { Trailer, TrailerResponse } from '../../models/Trailer';
import { MovieService } from '../../services/movie-service.service';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-movie-details',
  templateUrl: './movie-details.component.html',
  styleUrls: ['./movie-details.component.scss']
})

export class MovieDetailsComponent {

  constructor(private movieService: MovieService, private activatedRoute: ActivatedRoute) {}

  public movie!: Movie;
  public trailerResponse!: TrailerResponse;
  public trailers: Trailer[] | undefined = [];


  public getMovieTrailers() {
    const movie_id = Number(this.activatedRoute.snapshot.paramMap.get('id'));

    this.movieService.getMovieTrailers(movie_id).subscribe((response) => {
      this.trailerResponse = response;
      this.trailers = this.trailerResponse.results;
      
      if (this.trailers && this.trailers?.length) {
        this.trailers = this.trailers.slice(0, 5);
      } 
    });
  }

  public getMovieDetails() {
    const movie_id = Number(this.activatedRoute.snapshot.paramMap.get('id'));

    this.movieService.getMovieDetails(movie_id).subscribe((response) => {
      this.movie = response;

      // get movie trailers
      this.getMovieTrailers();
    });
  }

  ngOnInit() {
    this.getMovieDetails();
  }
}

模板:

<div *ngIf="trailers && trailers.length" class="mb-3">
  <h2 class="section-title">Trailers</h2>
  <app-trailer-carousel [trailers]="trailers"></app-trailer-carousel>
</div>

没有编译错误,但是,有一个令人惊讶的(对我来说)问题。

问题

安装了所需的结果,我在浏览器中收到此错误:

NG0904: unsafe value used in a resource URL context ... at TrailerCarouselComponent_div_3_Template (trailer-carousel.component.html:22:9)
有问题的行是 

src="https://www.youtube.com/embed/{{ video.key }}

 来自:

<iframe class="embed-responsive-item" src="https://www.youtube.com/embed/{{ video.key }}" ></iframe>
这对我来说更令人惊讶,因为我已经使用 Vue3 和 Typescript 

制作了这个应用程序并且没有遇到问题。

问题

    我做错了什么?
  1. 解决此问题最可靠的方法是什么?
javascript angular typescript
2个回答
0
投票
动态生成时可能存在不安全的 URL,因此我们需要确保经过清理的可信 URL 进入

src

,我们可以使用 Angular 的 
bypassSecurityTrustResourceUrl
 中的 
DomSanitizer
 来确保 URL 得到清理!

html

<iframe class="embed-responsive-item" [src]="trustUrl(video.key)" ></iframe>
ts

constructor(private sanitizer: DomSanitizer) {} ... ... trustUrl(key: string): string { return this.sanitizer.bypassSecurityTrustResourceUrl(`https://www.youtube.com/embed/${key}`) as string; } ...
    

0
投票
创建一个绕过 iframe URL 安全性的管道。

ng g p bypass-sanitize
import { Pipe, PipeTransform, inject } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
  name: 'bypassSanitize',
  standalone: true,
})
export class BypassSanitizePipe implements PipeTransform {
  private readonly domSanitizer = inject(DomSanitizer);

  //  constructor(private domSanitizier: DomSanitizer) {} old way but still working

  transform(value: string) {
    return this.domSanitizer.bypassSecurityTrustResourceUrl(value);
  }
}

由于您的组件没有独立属性,我假设您的应用程序是基于模块的。您可以在内部导入此管道

NgModule

将其添加到 NgModules 后,让我们使用这个管道:

<iframe class="embed-responsive-item" src="{{ 'https://www.youtube.com/embed/' + video.key | bypassSanitize }}" ></iframe>

警告:使用不受信任的用户数据调用此方法会使您的应用程序面临 XSS 安全风险!

© www.soinside.com 2019 - 2024. All rights reserved.