1. Function Introduction
- Support the first screen main picture rotation
- Support to click on the first screen to display the large image effect with rotation
- Supports video playback embedded in the first screen rotation diagram
2. Detailed explanation of core functions
Key Data Description
- VideoInfo
interface VideoInfo { videoId: string; // Video ID imageUrl: string; Duration: number; // Video length playUrl: string; // Video path}Copy the code
- wareImage
WareImageInfo { big: string; // small: string; / / insets}Copy the code
2.1 Component Entrance
- Component description
- Carousel first screen wheel casting component
- LargeCarousel click the big picture component shown in the first screen of the wheel cast picture
- Functional specifications
- Click the rote image on the first screen to display the large image, and automatically locate to the corresponding large image of the clicked image, through active state control
- State that
- ShowModel controls the switch that displays the larger image
- Initial toggle loading large graph JS (for lazy loading)
- Active Records the array subscript of the currently displayed image, which is used to click the interaction between the displayed large image and the first screen, as well as the video component, as described below
Export default (props: IProps) => {// To click on the interaction between the displayed large image and the first screen, record the array subscript of the currently displayed image const [active, setActive] = useState(0); Const [showModel, setShowModel] = useState(false); Const [initial, setInitial] = useState(false); useEffect(() => { if (showModel) setInitial(true); }, [showModel]); const { wareImage, videos, setImgOpacity } = props; let videoForMainImg! : VideoInfo; if (videos) { videoForMainImg = videos.filter((item) => item.videoType == '1')[0]; } return (<section className="jd-photo-album"> {/ / <Carousel {... { wareImage, setActive, active, setShowModel, showModel, setImgOpacity, }} {... (videoForMainImg ? Initial && showModel && (<Loading> <LargeCarousel {... { setShowModel, active, wareImage, setActive, showModel, }} /> </Loading> )} </section> ); };Copy the code
2.2 Main image on the first screen (Carousel)
- Component description
- JDPlayer video component
- Slider react-slick
https://github.com/akiran/react-slick
- Slider API
https://react-slick.neostack.com/docs/api
- Functional specifications
- If the Video has data, you need to display the Video play button on the first picture rotation chart on the first screen, click the button to automatically play the Video, slide the rotation chart while playing the Video, pause the Video, slide to the first picture, and then automatically play the Video. There are several key state controls
- State that
- The active parent component is passed in, and if there is a video active is 0 (the first one) is one of the conditions for displaying the video
- ShowPlayer controls the switch of video display to control whether to display the video or the main picture in the case of a video. The true state is one of the conditions for displaying the video
- Play Switch for controlling video playback
- ClickPause Specifies whether to manually click to pause a video. If yes, the video will continue to be paused after being paused. Otherwise, the video will play automatically
export default (props: IProps) => {
const { i18n } = usePublicContext();
const {wareImage,setActive,active,setShowModel,videoInfo,showModel} = props;
const slider = useRef<Slider>(null);
const [play, setPlay] = useState(false);
const [showPlayer, setShowPlayer] = useState(false);
const [clickPause, setClickPause] = useState(false);
//index changes trigger slide and trigger video play/pause state
useEffect(() = > {
if (slider.current) slider.current.slickGoTo(active);
if(active ! =0 && showPlayer) {
setPlay(false);
} else if (active == 0&&! clickPause && showPlayer && ! showModel) { setPlay(true);
}
}, [active, play, clickPause, showPlayer, showModel]);
const settings = {
infinite: false./ / not cycle
speed: 300.// Animation speed, in milliseconds
arrow: false.// Do not display arrows
beforeChange: (oldIndex: number, newIndex: number) = >{ setActive(newIndex); }};const handlePlayVideo = (e: React.MouseEvent) = > {
e.stopPropagation();
if(! videoAlert) {// When the user clicks to play the video, the prompt will be triggered to verify the wifi status
} else {
setShowPlayer(true);
setPlay(true); }};return (
<div className="jd-carousel">{(! showPlayer || active ! = = 0) && (<div className="page-nub">Image position currently displayed: 1/4</div>
)}
<Slider {. settings} ref={slider}>
{wareImage.map((item: any, index: number) => {
return (
<React.Fragment key={index}>
{index == 0 && showPlayer && videoInfo && (
<Loading>
<JDPlayer
video={videoInfo}
isPlay={play}
{.{
setShowPlayer.setClickPause,
}}
/>
</Loading>
)}
<div
onClick={(e: React.MouseEvent) = >{ setShowModel(true); }} style={{ display: index == 0 && showPlayer && videoInfo ? 'none' : 'block', }} > {index === 1 && ! showPlayer && videoInfo && videoInfo.videoType === '1' && (<span
className="video-time"
onClick={handlePlayVideo}
>Video time</span>
)}
<img
src={item.big}
onLoad={()= >{ if (index == 0) { //!!! SetImgOpacity (0); }}} / ></div>
</React.Fragment>
);
})}
</Slider>
</div>
);
};
Copy the code
2.3 Video Component (JDPlayer)
- Component description
- Video components:video-react
https://github.com/video-react/video-react
- API react-slick
https://video-react.js.org/components/player/
- Video components:video-react
- Functional specifications
- When the video is playing, slide the rote image and pause it. Then slide to the first image and the video automatically plays. Control the video playback and pause through isPlay
- Subscribe to the player state changes through the subscribeToStateChange method of React-slick. The error UI is displayed when there is an error. The switch of error UI is showError
- In the development of the component after the completion of loading immediately set the player, there will be a problem, and finally through setTimeout to solve (slightly fat hog flow), if there is a better way to also hope you big guy message
export default (props: {
video: VideoInfo;
isPlay: boolean;
setClickPause: (value: React.SetStateAction<boolean>) = > void;
setShowPlayer: (value: React.SetStateAction<boolean>) = > void; = > {})const { video, isPlay, setClickPause, setShowPlayer } = props;
const [screenWidth, setScreenWidth] = useState(0);
useEffect(() = > {
setScreenWidth(screen.width);
}, [setScreenWidth]);
const [jdPlayer, setJdPlayer] = useState<any>(null);
// Control video error display error UI state
const [showError, setShowError] = useState<boolean>(false);
useEffect(() = > {
if (jdPlayer) {
if (isPlay)
// There is a pit here, need setTimeou
setTimeout(() = > {
jdPlayer.play();
}, 0);
else jdPlayer.pause();
}
}, [isPlay, jdPlayer]);
// Get the latest state
const handleStateChange = (state: any) = > {
const { error, currentTime } = state;
/ / handle the Error
setShowError(error && error.code);
};
// Subscription player status changes
useEffect(() = > {
if (jdPlayer)
jdPlayer.subscribeToStateChange((state: any) = >
handleStateChange(state),
);
}, [jdPlayer]);
return (
<div className="jd-player">
{showError && (
<div className="error-content">
<div className="error-content-warp">
<div className="error-image"></div>
<div className="error-text">
error
</div>
</div>
</div>
)}
<div
className="close-video"
onClick={()= > {
setShowPlayer(false);
}}
>
close
</div>
<div
onClick={()= > {
setClickPause(isPlay);
}}
>
<Player
ref={(player: any) = > setJdPlayer(player)}
width={screenWidth}
height={screenWidth}
fluid={false}
videoId={video.videoId}
src={video.playUrl}
>
<ControlBar autoHide={false} />
</Player>
</div>
</div>
);
};
Copy the code
2.4 LargeCarousel
- Component description
- Slider react-slick
https://github.com/akiran/react-slick
- Slider API
https://react-slick.neostack.com/docs/api
- Functional specifications
- I wanted to use two groups of sliders, but it was troublesome. I found it easy and convenient to use custom dots. However, it should be noted that the react-slick does not display dot when there is only one slider
- State that
- The active parent component is passed in and changes when the larger image is switched
export default (props: {
wareImage: Array<WareImageInfo>;
active: number;
setActive: (value: React.SetStateAction<number>) = > void;
setShowModel: (value: React.SetStateAction<boolean>) = > void; = > {})const { wareImage, setActive, active, setShowModel } = props;
const pageSlider = useRef<Slider>(null);
const settings = {
dots: true.infinite: false.speed: 300.initialSlide: 0.// display slide 0 by default
beforeChange: (oldIndex: number, newIndex: number) = > {
setActive(newIndex);
},
appendDots: (dots: any) = > (
<div>
<ul style={{ margin: '0px' }}>{dots} </ul>
</div>
), // Customize the point template. Work with customPaging
customPaging: (i: number) = > <img src={wareImage[i].small}></img>}; useEffect(() = > {
// The larger image displayed according to the active Settings
if (pageSlider.current) pageSlider.current.slickGoTo(active);
}, [active]);
return (
<div className="jd-carousel-model">
<div className="jd-page-slider">
<div className="pg-header">
<i
className="header-back"
onClick={()= > {
setShowModel(false);
}}
></i>
<div className="page-bg">
<span>{active + 1}</span>
<span className="nub-bg">/</span>
<span>{wareImage.length}</span>
</div>
</div>
<Slider ref={pageSlider} {. settings} >
{wareImage.map((item: any, index: number) => {
return (
<div
key={index}
onClick={()= > {
setShowModel(false);
}}
>
<img
src={item.big}
style={{
width: '100%',
}}
/>
</div>
);
})}
</Slider>{/* Add dot */} {wareimage. length == 1 && (<div className="slick-dots">
<ul>
<li className="slick-active">
<img src={wareImage[0].small} />
</li>
</ul>
</div>
)}
</div>
</div>
);
};
Copy the code
3. Write at the end
Finally: Duck!