UNPKG

react-app-shell

Version:

react打包脚本和example, 这里的版本请忽略

340 lines (301 loc) 9.2 kB
import React, { PureComponent } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import * as tools from '../../../utils/tools'; import * as styles from './video.less'; import playImgSrc from '../../../public/images/feedback/play-btn.png'; /** * 视频播放, 兼容H5 IOS和安卓 */ class InnerVideoPlayer extends PureComponent { static propTypes = { width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), className: PropTypes.string, preload: PropTypes.string, poster: PropTypes.string, // 封面图片 src: PropTypes.string, // 视频资源地址 userAgent: PropTypes.string, // 服务端渲染时, 客户端浏览器请求的UA onPlay: PropTypes.func, // 函数: 播放回调 onPlaying: PropTypes.func, // 函数:播放中回调 onPause: PropTypes.func, // 函数: 播放暂停 onEnd: PropTypes.func, // 函数: 播放结束回调 onClose: PropTypes.func // 函数: 关闭回调 }; constructor(props) { super(props); // 添加容器 this.container = document.createElement('div'); document.body.appendChild(this.container); const { userAgent } = this.props; this.isIOS = tools.isIOS(userAgent); // 是否是iOS系统 this.isAndroid = tools.isAndroid(userAgent); // 是否是Android系统 this.status = ''; // 状态, reset 已重置, play 已播放, 空字符串/默认值 没有播放过 } componentDidMount() { // 禁止滚动 this.container.addEventListener('touchmove', this.preventTouchMove, false); // 设置内联播放 if (this.isIOS) { this.player.setAttribute('playsinline', true); // 禁止 iPhone Safari 视频自动全屏 this.player.setAttribute('webkit-playsinline', true); // 禁止 iPhone Safari 视频自动全屏 } else { this.player.setAttribute('x5-playsinline', true); } // 播放 this.player.play(); } componentWillUnmount() { clearTimeout(this.playTimer); // 取消事件监听 this.container.removeEventListener('touchmove', this.preventTouchMove, false); document.body.removeChild(this.container); } /** * 监听终端横竖屏切换 */ // watchOrientation = () => { // if (window.orientation === 90 || window.orientation === -90) { // this.fullScreen(); // } else { // this.exitFullScreen(); // } // console.log(window.orientation, 111); // } // /** // * 进入全屏 // */ // fullScreen = () => { // const ele = document.documentElement; // if (ele.requestFullscreen) { // ele.requestFullscreen(); // } else if (ele.mozRequestFullScreen) { // ele.mozRequestFullScreen(); // } else if (ele.webkitRequestFullScreen) { // ele.webkitRequestFullScreen(); // } else if (ele.msRequestFullscreen) { // ele.msRequestFullscreen(); // } // // alert(ele.requestFullscreen); // } // /** // * 退出全屏 // */ // exitFullScreen = () => { // var de = document; // if (de.exitFullscreen) { // de.exitFullscreen(); // } else if (de.mozCancelFullScreen) { // de.mozCancelFullScreen(); // } else if (de.webkitCancelFullScreen) { // de.webkitCancelFullScreen(); // } else if (de.msExitFullscreen) { // de.msExitFullscreen(); // } // } player = null; playTimer = null; preventTouchMove = (event) => { event.stopPropagation(); event.preventDefault(); }; /** * 开始播放 */ handlePlay = () => { const { onPlay } = this.props; onPlay && onPlay(); this.status = 'play'; }; /** * 视频播放中 */ handlePlaying = () => { const { onPlaying } = this.props; onPlaying && onPlaying(); }; /** * 暂停 */ handlePause = () => { const { onPause } = this.props; onPause && onPause(); }; /** * 播放结束 */ handleEnded = () => { const { onEnd } = this.props; if (this.isAndroid) { // 先播放 this.player.play(); // 延迟关闭, 解决安卓全屏播放结束后的广告问题 this.playTimer = setTimeout(() => { this.player.pause(); }, 60); } onEnd && onEnd(); }; /** * 关闭视频播放层 */ handleClose = () => { this.changeViewHeight('visible', 'auto'); this.props.onClose && this.props.onClose(); }; /** * IOS视频播放器 * 使用原生播放按钮 * @returns {*} */ renderIOSContent = () => { const { width, src, poster, className, preload } = this.props; return ( <div className={styles.video}> <video ref={(player) => { this.player = player; }} width={width} style={{ objectFit: 'fill' }} controls={true} poster={poster} preload={preload} className={className} onPlay={this.handlePlay} onPause={this.handlePause} onPlaying={this.handlePlaying} onEnded={this.handleEnded} > <source src={src} type="video/mp4" /> 当前浏览器不支持最新的video播放 </video> </div> ); }; /** * 安卓视频播放器 * @returns {*} */ renderAndroidContent = () => { const { width, src, poster, className, preload } = this.props; return ( <div className={styles.video}> <video ref={(player) => { this.player = player; }} controls={false} width={width} style={{ objectFit: 'fill' }} poster={poster} src={src} preload={preload} className={className} onPlay={this.handlePlay} onPause={this.handlePause} onPlaying={this.handlePlaying} onEnded={this.handleEnded} > 当前浏览器不支持最新的video播放 </video> </div> ); }; renderVideo = () => { return ( <div className={styles.videoBox} id="video-box"> <div className={styles.close} onClick={this.handleClose}> × </div> {this.isIOS ? this.renderIOSContent() : this.renderAndroidContent()} </div> ); }; changeViewHeight = (over, height) => { document.getElementsByTagName('body')[0].style.overflow = over; document.getElementsByTagName('body')[0].style.height = height; }; render() { this.changeViewHeight('hidden', '100px'); return ReactDOM.createPortal(this.renderVideo(), this.container); } } /** * 图片视频播放器 */ class VideoImagePlayer extends PureComponent { static propTypes = { width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), className: PropTypes.string, preload: PropTypes.string, poster: PropTypes.string, // 封面图片 src: PropTypes.string, // 视频资源地址 userAgent: PropTypes.string, // 服务端渲染时, 客户端浏览器请求的UA onPlay: PropTypes.func, // 函数: 播放回调 onPlaying: PropTypes.func, // 函数:播放中回调 onPause: PropTypes.func, // 函数: 播放暂停 onEnd: PropTypes.func // 函数: 播放结束回调 }; static defaultProps = { width: 300, // 视频宽高比为: 3:4 height: 400, // IOS、android 高度自适应 className: '', preload: 'metadata', // auto: 默认下载视频 metadata: 只提取视频元数据 none: 不会预加载视频 poster: '', src: '', userAgent: '', onPlay: () => {}, onPlaying: () => {}, onPause: () => {}, onEnd: () => {} }; constructor(props) { super(props); const { userAgent } = this.props; this.isIOS = tools.isIOS(userAgent); // 是否是iOS系统 this.isAndroid = tools.isAndroid(userAgent); // 是否是Android系统 this.status = ''; // 状态, reset 已重置, play 已播放, 空字符串/默认值 没有播放过 this.state = { status: 'hide' // 是否显示视频播放 }; } componentDidMount() { this.clientWidth = document.body.clientWidth || document.documentElement.clientWidth; } /** * 点击图片的播放按钮 */ handleImagePlay = (event) => { event.stopPropagation(); this.setState({ status: 'show' }); }; /** * 关闭视频播放层 */ handleClose = () => { this.setState({ status: 'jode' }); }; render() { const { status } = this.state; const { poster } = this.props; return ( <> <div className={styles.imgBox}> <img src={poster} className={classNames(styles.videoImage, 'lazyload')} /> <img src={playImgSrc} className={styles.playButton} onClick={this.handleImagePlay} /> </div> {status === 'show' ? ( <InnerVideoPlayer onClose={this.handleClose} {...this.props} width={this.clientWidth} /> ) : null} </> ); } } export default VideoImagePlayer;