项目需要一个列表循环播放视频的功能,使用的是阿里云私有加密,先说一下实现思路。
- 请求视频列表数据
- 首次默认第一条视频列表数据
- 自动播放第一条数据
- 播放结束自动更新索引值加载下一个视频。
因为播放器是需要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} </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、首次网页加载需要点击才能进行自动播放;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。