1

项目需要一个列表循环播放视频的功能,使用的是阿里云私有加密,先说一下实现思路。

  • 请求视频列表数据
  • 首次默认第一条视频列表数据
  • 自动播放第一条数据
  • 播放结束自动更新索引值加载下一个视频。

因为播放器是需要dom结构加载的,所以需要使用componentDidMount方法加载渲染播放器,
我们页面加载的第一次请求将通过它实现。

阿里云播放器自定义组件
我给自定义播放组件提供了componentWillReceiveProps方法,用于跟踪配置文件变化,重载播放器播放视频。

接下来是实现的代码

import React from 'react';
import Router, {withRouter} from 'next/router'
import styles from './index.module.scss'
import Aliplayer from "@/components/aliplay";
import Head from 'next/head'


export default withRouter(
    class PlayList extends React.Component {
        constructor(props) {
            super(props);
            this.handleCoursePlayBtnClick = this.handleCoursePlayBtnClick.bind(this)
            this.videoPlayer = React.createRef();
        }

        state = {
            showDataSource: [],
            showPlayer: false,
            instance: null,
            playNextStatus: true,
            selectedPlayIndex: 0,
        }

        componentDidMount() {
            this.init()
        }

        async init() {
            const response = await api.getList()
            try {
                var data = response.data || []
                if (data.length > 0) {
                    let firstVideo = data[0]
                    this.setState({selectedPlayIndex: 0})
                    this.getInfo(firstVideo.vid)
                }
                this.setState({showDataSource: data})
            } catch (e) {

            }

        }

        handleCoursePlayBtnClick(index, vid) {
            this.getInfo(vid)
            this.setState({selectedPlayIndex: index})
        }

        async getInfo(vid) {
            var playerConfig = {
                vid: "",
                playauth: "",
                width: '100%',
                height: '100%',
                autoplay: true, // 自动播放
                useH5Prism: true, // 播放器类型:html5
                preload: true,
            }
            if (!vid) {
                throw Error("未提供vid")
            }
            var video = {}
            const responseVideo = await api.getAuth(video.videoSourceId)
            try {
                playerConfig.playauth = responseVideo.playAuth
            } catch (e) {
                delete playerConfig.playauth
                delete playerConfig.vid
            }

            this.setState({
                video: video,
                playerConfig: playerConfig,
            })
            // console.log("课程加载完成", playerConfig,this.state.showPlayer)
        }

        onGetInstance = (player) => {
            let that = this
            player.on('ended', async function (e) {
                if (that.state.playNextStatus) {
                    that.setState({playNextStatus: false})
                    that.playNextVideo()
                }
                setTimeout(() => {
                    that.setState({playNextStatus: true})
                    clearTimeout()
                }, 800)
                // console.log("播放器结束播放", e)
            })
            player.on('playing', function (e) {
                console.log("播放中")
            })
            player.on('ready', function (e) {
                console.log("视频准备就绪,即将播放")
            });
            player.on('error', function (e) {
                console.log("出现错误", e)
            });
            player.on('autoplay', function (data) {
                //可以自动播放 data.paramData
            })
        }

        playNextVideo = () => {
            let that = this
            const dataSource = that.state.dataSource
            let index = (dataSource.length > that.state.selectedPlayIndex + 1) ? (that.state.selectedPlayIndex + 1) : 0;
            let id = dataSource[index] && dataSource[index].id
            that.getInfo(id)
            that.setState({selectedPlayIndex: index})
        }

        render() {
            const {showDataSource, selectedPlayIndex, playerConfig, showPlayer} = this.state
            return (
                <div className="match video-page">
                    <Head>
                        <script src={'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js'}
                                type={'text/javascript'}/>
                        <link href={'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css'}
                              rel={'stylesheet'}/>
                    </Head>
                    <div className={styles.main + " row match content-start"}>
                        <div className={styles.videoListBox + "  h-match cell-scroll-y"}>
                            <div className={styles.listBtn}>
                                <img className={styles.listBtnIcon} alt="" src={"/logo_sign.png"}/>
                            </div>
                            <div className="col content-start match">
                                <ul className={styles.videoList}>
                                    {showDataSource && showDataSource.map((video, i) => {
                                        return (
                                            <li className={styles.videoCard + " " + (selectedPlayIndex === i && styles.videoCardActived)}
                                                key={i}>
                                                <div className="w-match p-2 col">
                                                    <div className={styles.imageBox}
                                                         onClick={() => this.handleCoursePlayBtnClick(i, video.id)}>
                                                        <img className={styles.videoImage} alt=""
                                                             src={video.videoCover}/>
                                                    </div>
                                                    <div className={styles.title}
                                                         onClick={() => this.handleCoursePlayBtnClick(i, video.id)}>{video.title}&nbsp;</div>
                                                </div>
                                            </li>
                                        )
                                    })}
                                </ul>
                            </div>
                        </div>
                        <div className={styles.playerContainer + " match bg-black"}>
                            <div className={styles.videoContainer}>
                                <div ref={this.videoPlayer} style={{height: this.state.height}}
                                     className={"col " + styles.videoBox}>
                                    {(showPlayer && playerConfig) && <Aliplayer
                                        config={playerConfig}
                                        onGetInstance={instance => this.onGetInstance(instance)}
                                    />}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            );
        }
    }
)

这里是开发过程中发现并解决的几个点:
1、播放器在结束播放并进行下一个视频播放时,会多次触发ended事件,其问题根源就是该播放器状态为结束时,我进行切换下个视频,此时ended事件再次或多次激活,导致跳过多个视频。
2、循环播放列表需要对index索引判断,进行播放视频内容更新;

目前的解决方案是做一个状态标记,通过计时器解决该问题;

这里是开发过程中发现未解决的几个点:
1、首次网页加载需要点击才能进行自动播放;


泉州牧码人
73 声望4 粉丝

前端工程师