reactjs 以给定的持续时间响应图像和视频播放器

izkcnapc  于 2022-11-04  发布在  React
关注(0)|答案(2)|浏览(124)

我是新的React,我想有一个简单的媒体播放器(图像和视频),自动开始显示图像或播放JSON文件中给定的视频。我的代码是:

import axios from 'axios'
import React from 'react'

import './App.css'

type MyProps = {}
type MyState = {currentImage: number; type: string[]; duration: number[]; url: string[]}
export class App extends React.Component<MyProps, MyState> {
    constructor(props: any) {
        super(props)
        this.switchImage = this.switchImage.bind(this)
        this.state = {currentImage: 0, type: [], duration: [], url: []}
    }

    async getSource() {
        let durationArray: number[] = []
        let urlArray: string[] = []
        let typeArray: string[] = []
        let sources = [
            {
                name: 'Person 1',
                type: 'image',
                url: 'https://loremflickr.com/320/240/cat',
                duration: 5,
            },
            {
                name: 'Person 2',
                type: 'image',
                url: 'https://loremflickr.com/320/240/dog',
                duration: 3,
            },
            {
                name: 'Video 1',
                type: 'video',
                url: 'https://file-examples.com/storage/fe07f859fd624073f9dbdc6/2017/04/file_example_MP4_480_1_5MG.mp4',
                duration: 7,
            },
        ]

        sources.forEach((source: {url: string; type: string; duration: number}) => {
            urlArray.push(source.url)
            typeArray.push(source.type)
            durationArray.push(source.duration)
        })
        this.setState({url: urlArray, duration: durationArray, type: typeArray})
    }

    switchImage() {
        if (this.state.currentImage < this.state.url.length - 1) {
            this.setState({currentImage: this.state.currentImage + 1})
        } else {
            this.setState({currentImage: 0})
        }
        return this.state.currentImage
    }

    componentDidMount() {
        this.getSource()
        setInterval(this.switchImage, 5000)
    }

    render() {
        const sourceType = this.state.type[this.state.currentImage]
        console.log(sourceType)
        return (
            <div className="player">
                {sourceType === 'image' ? (
                    <img src={this.state.url[this.state.currentImage]} width="auto" height="auto" />
                ) : (
                    <video autoPlay src={this.state.url[this.state.currentImage]} width="auto" height="auto"></video>
                )}
            </div>
        )
    }
}

从JSON源中,我获得了每个源的 urldurationtype,并以给定的持续时间播放图像或视频。
1:是否可以在给定的持续时间内播放每个图像,然后制作下一个。
2:我应该把它转换成一个函数组件吗?还是把整个代码移到一个新的组件中?

8dtrkrch

8dtrkrch1#

我在你的应用程序上修改了一些东西。

import { Component } from "react";
import "./styles.css";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sources: undefined,
      currentImage: -1
    };
  }

  getSource = async () => {
    return new Promise((resolve, reject) => {
      let sources = [
        {
          name: "Person 1",
          type: "image",
          url: "https://loremflickr.com/320/240/cat",
          duration: 5
        },
        {
          name: "Person 2",
          type: "image",
          url: "https://loremflickr.com/320/240/dog",
          duration: 3
        },
        {
          name: "Video 1",
          type: "video",
          url:
            "https://file-examples.com/storage/fe07f859fd624073f9dbdc6/2017/04/file_example_MP4_480_1_5MG.mp4",
          duration: 7
        }
      ];
      resolve(sources);
    });
  };

  async componentDidMount() {
    let mySources = await this.getSource();
    console.log("mySources", mySources);
    this.setState(
      {
        sources: mySources,
        currentImage: 0
      },
      () => {
        this.displayNext(mySources[0].duration * 1000);
      }
    );
  }

  displayNext = (time) => {
    console.log(this.state.currentImage);
    setTimeout(() => {
      this.setState(
        {
          currentImage:
            this.state.currentImage == this.state.sources.length - 1
              ? 0
              : this.state.currentImage + 1
        },
        () => {
          this.displayNext(
            this.state.sources[this.state.currentImage].duration * 1000
          );
        }
      );
    }, time);
  };

  render() {
    const _sources = this.state.sources;
    const _index = this.state.currentImage;
    return _sources && _index >= 0 ? (
      <div className="player">
        {_sources[_index].type === "image" ? (
          <img src={_sources[_index].url} width="auto" height="auto" />
        ) : (
          <video
            autoPlay
            src={_sources[_index].url}
            width="auto"
            height="auto"
          ></video>
        )}
      </div>
    ) : (
      <></>
    );
  }
}

说明:
因此,不要使用setInterval,而要使用setTimeout。在第一个图像开始显示后'x'秒触发第一个超时。这个'x'秒的值将是您想要显示图像的持续时间值。下一步,要使其递归,一旦调用超时,就更改状态并设置下一个超时!

bnl4lu3b

bnl4lu3b2#

对于任何在Vue中寻找实现的人:

<template>
  <img :src="currentImgSrc">
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, nextTick, withDefaults, defineProps } from 'vue';

type Image = string;
type Images = Array<Image>;

interface Props {
  images: Images;
  duration?: number; // in seconds
}

const props = withDefaults(defineProps<Props>(), {
  duration: 1,
});

const state = reactive<{
  imageElements: Array<HTMLImageElement>;
  currentImageIndex: number;
  numberOfLoadedImages: number;
  error: string;
}>({
  imageElements: [],
  currentImageIndex: -1,
  numberOfLoadedImages: 0,
  error: '',
});

const currentImgSrc = computed(() => {
  if (state.error) {
    return '';
  } else {
    return state.imageElements[state.currentImageIndex]?.src || '';
  }
});

const fetchImagesAndTriggerPlayback = async () => {
  props.images.forEach((_, index) => {
    const image = new Image();

    image.src = props.images[index];

    image.onload = async () => {
      state.numberOfLoadedImages++;

      await nextTick();

      if (state.numberOfLoadedImages === props.images.length) {
        showNextImage(); // Trigger playback
      }
    };

    image.onerror = () => {
      state.error = 'Something went wrong';
    };

    state.imageElements = [...state.imageElements, image];
  });
};

const showNextImage = () => {
  setTimeout(async () => {
    state.currentImageIndex =
      state.currentImageIndex === state.imageElements.length - 1 ? 0 : state.currentImageIndex + 1;

    await nextTick();

    showNextImage();
  }, props.duration * 1000);
};

onMounted(() => {
  fetchImagesAndTriggerPlayback();
});
</script>

相关问题