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/
  • 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!