立即在 React 中交换视频组件
Swap video components in React with no delay
我有一个显示 video
元素的应用程序。
我希望用户能够点击一个按钮并观看另一个视频。但是,在更改 src
属性时,在呈现下一个 mp4 时会出现轻微的白色闪光。
为了解决这个问题,我相信我需要加载一个,预加载另一个并在准备好时更改它们。
我不确定如何在 React 中执行此操作。
import React, { Component } from 'react';
import './App.css'
import one from './one.mp4';
import two from './two.mp4';
import three from './three.mp4';
import four from './four.mp4';
class App extends Component {
playlist = [one, two, three, four]
shuffle = (array) => array.sort(() => Math.random() - 0.5);
getRandomVideo = () => this.shuffle(this.playlist)[Math.floor(Math.random() * this.playlist.length)]
state = {
playerOne: {
isVisible: true,
inputSrc: this.getRandomVideo()
},
playerTwo: {
isVisible: false,
inputSrc: this.getRandomVideo()
}
}
onTap = () => this.setState(prevState => ({
playerOne: {
isVisible: !prevState.playerOne.isVisible,
inputSrc: this.getRandomVideo()
},
playerTwo: {
isVisible: !prevState.playerTwo.isVisible,
inputSrc: this.getRandomVideo()
}
}));
render() {
const { playerOne, playerTwo } = this.state
return (
<div>
<div className="outer">
<button onClick={this.onTap}>Toggle</button>
{playerOne.isVisible && <VideoPlayer src={playerOne.inputSrc} /> }
{playerTwo.isVisible && <VideoPlayer src={playerTwo.inputSrc} /> }
</div>
</div>
)
}
}
export default App
const VideoPlayer = ({ src }) => {
return (
<video key={src} preload autoPlay loop muted><source src={src} type='video/mp4' /></video>
)
}
您可以在 video
元素中设置 background
属性 并使用一些 svg 动画来处理闪烁。
例子
const { useState, useEffect } = React;
const getVideos = () => Promise.resolve([
{id: 1,
src: "https://archive.org/download/BigBuckBunny_124/Content/big_buck_bunny_720p_surround.mp4"},
{
id: 2,
src: "https://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"}
])
const App = () => {
const [{videos, video}, setData] = useState({
videos: [],
video: {
id: -1,
src: null
}
});
useEffect(() => {
let isUnmounted = false;
getVideos().then(videos => {
if(isUnmounted) {
return;
}
setData(data => ({
...data,
videos,
video: videos[0]
}))
})
return () => {
isUnmounted = true;
}
}, [])
const onNextVideo = () => {
setData(data => ({
...data,
video: data.videos.find(pr => pr.id !== video.id)
}))
}
return <div>
<video preload="true" autoPlay loop muted key={video.id}>
<source
src={video.src}
type="video/mp4"/>
</video>
<div>
<button onClick={onNextVideo}>Next Video</button>
</div>
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
video {
width: 300px;
height: 200px;
object-fit: cover;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
background-color: black;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSIgdmlld0JveD0iMCAwIDQ1IDQ1IiBzdHJva2U9IiNmZmYiPgo8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJibGFjayIvPgogICAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxIDEpIiBzdHJva2Utd2lkdGg9IjIiPgogICAgICAgIDxjaXJjbGUgY3g9IjIyIiBjeT0iMjIiIHI9IjExLjA2NTYiIHN0cm9rZS1vcGFjaXR5PSIwIj4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iciIgYmVnaW49IjEuNXMiIGR1cj0iM3MiIHZhbHVlcz0iNjsyMiIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3Ryb2tlLW9wYWNpdHkiIGJlZ2luPSIxLjVzIiBkdXI9IjNzIiB2YWx1ZXM9IjE7MCIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3Ryb2tlLXdpZHRoIiBiZWdpbj0iMS41cyIgZHVyPSIzcyIgdmFsdWVzPSIyOzAiIGNhbGNNb2RlPSJsaW5lYXIiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIi8+CiAgICAgICAgPC9jaXJjbGU+CiAgICAgICAgPGNpcmNsZSBjeD0iMjIiIGN5PSIyMiIgcj0iMTkuMDY1NiIgc3Ryb2tlLW9wYWNpdHk9IjAiPgogICAgICAgICAgICA8YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJyIiBiZWdpbj0iM3MiIGR1cj0iM3MiIHZhbHVlcz0iNjsyMiIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3Ryb2tlLW9wYWNpdHkiIGJlZ2luPSIzcyIgZHVyPSIzcyIgdmFsdWVzPSIxOzAiIGNhbGNNb2RlPSJsaW5lYXIiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIi8+CiAgICAgICAgICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS13aWR0aCIgYmVnaW49IjNzIiBkdXI9IjNzIiB2YWx1ZXM9IjI7MCIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICA8L2NpcmNsZT4KICAgICAgICA8Y2lyY2xlIGN4PSIyMiIgY3k9IjIyIiByPSIzLjc5OTE4Ij4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iciIgYmVnaW49IjBzIiBkdXI9IjEuNXMiIHZhbHVlcz0iNjsxOzI7Mzs0OzU7NiIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICA8L2NpcmNsZT4KICAgIDwvZz4KPC9zdmc+");
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
我有一个显示 video
元素的应用程序。
我希望用户能够点击一个按钮并观看另一个视频。但是,在更改 src
属性时,在呈现下一个 mp4 时会出现轻微的白色闪光。
为了解决这个问题,我相信我需要加载一个,预加载另一个并在准备好时更改它们。
我不确定如何在 React 中执行此操作。
import React, { Component } from 'react';
import './App.css'
import one from './one.mp4';
import two from './two.mp4';
import three from './three.mp4';
import four from './four.mp4';
class App extends Component {
playlist = [one, two, three, four]
shuffle = (array) => array.sort(() => Math.random() - 0.5);
getRandomVideo = () => this.shuffle(this.playlist)[Math.floor(Math.random() * this.playlist.length)]
state = {
playerOne: {
isVisible: true,
inputSrc: this.getRandomVideo()
},
playerTwo: {
isVisible: false,
inputSrc: this.getRandomVideo()
}
}
onTap = () => this.setState(prevState => ({
playerOne: {
isVisible: !prevState.playerOne.isVisible,
inputSrc: this.getRandomVideo()
},
playerTwo: {
isVisible: !prevState.playerTwo.isVisible,
inputSrc: this.getRandomVideo()
}
}));
render() {
const { playerOne, playerTwo } = this.state
return (
<div>
<div className="outer">
<button onClick={this.onTap}>Toggle</button>
{playerOne.isVisible && <VideoPlayer src={playerOne.inputSrc} /> }
{playerTwo.isVisible && <VideoPlayer src={playerTwo.inputSrc} /> }
</div>
</div>
)
}
}
export default App
const VideoPlayer = ({ src }) => {
return (
<video key={src} preload autoPlay loop muted><source src={src} type='video/mp4' /></video>
)
}
您可以在 video
元素中设置 background
属性 并使用一些 svg 动画来处理闪烁。
例子
const { useState, useEffect } = React;
const getVideos = () => Promise.resolve([
{id: 1,
src: "https://archive.org/download/BigBuckBunny_124/Content/big_buck_bunny_720p_surround.mp4"},
{
id: 2,
src: "https://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"}
])
const App = () => {
const [{videos, video}, setData] = useState({
videos: [],
video: {
id: -1,
src: null
}
});
useEffect(() => {
let isUnmounted = false;
getVideos().then(videos => {
if(isUnmounted) {
return;
}
setData(data => ({
...data,
videos,
video: videos[0]
}))
})
return () => {
isUnmounted = true;
}
}, [])
const onNextVideo = () => {
setData(data => ({
...data,
video: data.videos.find(pr => pr.id !== video.id)
}))
}
return <div>
<video preload="true" autoPlay loop muted key={video.id}>
<source
src={video.src}
type="video/mp4"/>
</video>
<div>
<button onClick={onNextVideo}>Next Video</button>
</div>
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
video {
width: 300px;
height: 200px;
object-fit: cover;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
background-color: black;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSIgdmlld0JveD0iMCAwIDQ1IDQ1IiBzdHJva2U9IiNmZmYiPgo8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJibGFjayIvPgogICAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxIDEpIiBzdHJva2Utd2lkdGg9IjIiPgogICAgICAgIDxjaXJjbGUgY3g9IjIyIiBjeT0iMjIiIHI9IjExLjA2NTYiIHN0cm9rZS1vcGFjaXR5PSIwIj4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iciIgYmVnaW49IjEuNXMiIGR1cj0iM3MiIHZhbHVlcz0iNjsyMiIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3Ryb2tlLW9wYWNpdHkiIGJlZ2luPSIxLjVzIiBkdXI9IjNzIiB2YWx1ZXM9IjE7MCIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3Ryb2tlLXdpZHRoIiBiZWdpbj0iMS41cyIgZHVyPSIzcyIgdmFsdWVzPSIyOzAiIGNhbGNNb2RlPSJsaW5lYXIiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIi8+CiAgICAgICAgPC9jaXJjbGU+CiAgICAgICAgPGNpcmNsZSBjeD0iMjIiIGN5PSIyMiIgcj0iMTkuMDY1NiIgc3Ryb2tlLW9wYWNpdHk9IjAiPgogICAgICAgICAgICA8YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJyIiBiZWdpbj0iM3MiIGR1cj0iM3MiIHZhbHVlcz0iNjsyMiIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0ic3Ryb2tlLW9wYWNpdHkiIGJlZ2luPSIzcyIgZHVyPSIzcyIgdmFsdWVzPSIxOzAiIGNhbGNNb2RlPSJsaW5lYXIiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIi8+CiAgICAgICAgICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS13aWR0aCIgYmVnaW49IjNzIiBkdXI9IjNzIiB2YWx1ZXM9IjI7MCIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICA8L2NpcmNsZT4KICAgICAgICA8Y2lyY2xlIGN4PSIyMiIgY3k9IjIyIiByPSIzLjc5OTE4Ij4KICAgICAgICAgICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iciIgYmVnaW49IjBzIiBkdXI9IjEuNXMiIHZhbHVlcz0iNjsxOzI7Mzs0OzU7NiIgY2FsY01vZGU9ImxpbmVhciIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgICA8L2NpcmNsZT4KICAgIDwvZz4KPC9zdmc+");
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>