【问题标题】:Facing difficulty in Implementing Carousel when iterating through an array遍历数组时面临实现轮播的困难
【发布时间】:2021-01-19 07:41:24
【问题描述】:

我想使用我的 Vidoes Array 中的数据实现轮播,我无法获得所需的输出,而是同时渲染 Array 中的所有视频

<div id="carouselExampleSlidesOnly" class="carousel slide" data-bs-ride="carousel">
          <div class="carousel-inner">
            {Videos}
        </div>
      </div>




This is my Videos array

const Videos = VIDEOS.map((vid) => {
      if(vid.name=="Video1"){
        vari=true;
        }
      return (
        <div
         className={vari?"carousel-item active":"carousel-item"}
          style={{ width: "25vw", height: "5vh", background: "#F1F1F1",margin:"auto" }}
        >
          <img src="..." class="card-img-top" alt={vid.name}></img>
        </div>
      );
    });






【问题讨论】:

    标签: html css reactjs carousel bootstrap-5


    【解决方案1】:

    我几天前刚刚完成了这项工作。但尚未缩短、优化和添加视频支持

    这是我的代码:

    import React, { useEffect, useState } from 'react';
    import "./MediaViewer.css";
    import { useGlobalObj, globalObj } from 'logic/zergski-global-object';
    
    // content JSON
    import { mediaJSON } from 'logic/content-collections';
    
    // components
    import Anchor from 'shared/Anchor';
    
    let current = 'can1';
    let canvas = {
        can1: {
            pos: 'center',
            trans: true,
            source: mediaJSON[0].src,
        },
        can2: {
            pos: 'right',
            trans: true,
            source: mediaJSON[1].src,
        },
        can3: {
            pos: 'left',
            trans: false,
            source: mediaJSON[mediaJSON.length-1].src,
        }
    }
    
    // iterator
    // TODO! add settings
    const iterator = ( array, setState, initIndex ) => {
        let index = initIndex;
        let count = array.length - 1;   // content count
        let nextSource = index+2;       // next imagesource to load
        let nextCanvas = 0; //  canvas position
        let nextImageSource = nextCanvas - 1;
    
        return {
            next() {
                index = index === count ? 0 : ++index;
                nextSource = index+1 > count ? 0 : index+1;
    
                Object.entries(canvas).forEach( c => {
                    canvas[c[0]].pos = c[1].pos === 'center' ? 'left' : c[1].pos === 'right' ? 'center' : 'right';
                    c[1].pos === 'center' && (current = c[0]);
                    if ( c[1].pos === 'right' ) {
                        canvas[c[0]].trans = false;
                        canvas[c[0]].source = mediaJSON[nextSource].src;
                    } else {
                        canvas[c[0]].trans = true;
                    }
                });
    
                setState({
                    ...canvas,
                    counter: index+1,
                });
            },
            prev() {
                index = index === 0 ? count : --index;
                nextSource = index-1 < 0 ? count : index-1;
    
                Object.entries(canvas).forEach( c => {
                    canvas[c[0]].pos = c[1].pos === 'center' ? 'right' : c[1].pos === 'left' ? 'center' : 'left';
                    c[1].pos === 'center' && (current = c[0]);
                    if ( c[1].pos === 'left' ) {
                        canvas[c[0]].trans = false;
                        canvas[c[0]].source = mediaJSON[nextSource].src;
                    } else {
                        canvas[c[0]].trans = true;
                    }
                });
    
                setState({
                    ...canvas,
                    counter: index+1,
                });
            }
        }
    }
    
    
    
    var lastTouch = 0;
    var content = Object.create(null);
    
    // component for viewing images, videos and documents
    const MediaViewer = props => {
        const mediaViewer = {
            display: 'hidden',
            contentIndex: 0,
            initialState: { display: 'hidden' },
        }
        const [ viewerState, setViewerState ] = useGlobalObj({ mediaViewer });
        const [ state, setState ] = useState({
            ...canvas,
            counter: 1,
        });
        const [ touchState, setTouchState ] = useState({
            touch: false,
            movement: 0,
        });
    
    
    
    
        if ( viewerState.display === 'show' ) {
            document.body.classList.add('scroll-lock');
            setTimeout(()=>{
                globalObj.mediaViewer.setState({ display: 'visible' });
            }, 50)
        }
    
        useEffect(() => {
            const { display, index } = viewerState;
            if ( display === 'show' ) {
                content = iterator( mediaJSON, setState, index );
    
                current = 'can1';
                canvas = {
                    can1: {
                        pos: 'center',
                        trans: false,
                        source: mediaJSON[index].src,
                    },
                    can2: {
                        pos: 'right',
                        trans: false,
                        source: mediaJSON[index === mediaJSON.length-1 ? 0 : index+1].src,
                    },
                    can3: {
                        pos: 'left',
                        trans: false,
                        source: mediaJSON[index === 0 ? mediaJSON.length-1 : index-1].src,
                    }
                }
    
                setState({
                    ...canvas,
                    counter: index+1,
                })
            }
    
        }, [viewerState]);
    
        const handleClose = () => {
            globalObj.mediaViewer.setState({ display: 'hide' });
            setTimeout(()=>{
                globalObj.mediaViewer.setState({ display: 'hidden' });
            }, 400)
    
            document.body.classList.remove('scroll-lock');
        }
    
    
    
        // input handlers
        const handleMovement = ( delta, touch=false ) => {
            let nextMovement = touchState.movement - delta;
    
    
            canvas[current].trans = false;
            canvas[current].movement = nextMovement;
            setTouchState({ movement: nextMovement });
        }
        // touch
        const handleTouchStart = (e) => {
            lastTouch = e.nativeEvent.touches[0].clientX;
        }
        const handleTouchMove = (e) => {
            const delta = lastTouch - e.nativeEvent.touches[0].clientX;
            lastTouch = e.nativeEvent.touches[0].clientX;
    
            handleMovement(Math.floor(delta), true);
        }
        const handleTouchEnd = (e) => {
            touchState.movement < -50 ? content.next() : touchState.movement > 50 && content.prev();
            lastTouch = 0;
    
            canvas[current].trans = true;
            setTouchState({ movement: 0 });
        }
    
        return (
    
            <div className={ `Media-Viewer ${ viewerState.display }` }
                onTouchStart={ handleTouchStart }
                onTouchMove={ handleTouchMove }
                onTouchEnd={ handleTouchEnd }
            >
    
                <img className={ `Media-Viewer-Content ${ state.can1.pos }` } alt={ '' }
                    src={ state.can1.source }
    
                    style={{
                        transform: current === 'can1' ? `translateX(${ touchState.movement }px)` : '',
                        transitionDuration: `${ canvas.can1.trans ? '' : '0s' }`,
                    }}
                />
                <img className={ `Media-Viewer-Content ${ state.can2.pos }` } alt={ '' }
    
                    src={ state.can2.source }
    
                    style={{
                        transform: current === 'can2' ? `translateX(${ touchState.movement }px)` : '',
                        transitionDuration: `${ canvas.can2.trans ? '' : '0s' }`,
                    }}
                />
                <img className={ `Media-Viewer-Content ${ state.can3.pos }` } alt={ '' }
                    src={ state.can3.source }
    
                    style={{
                        transform: current === 'can3' ? `translateX(${ touchState.movement }px)` : '',
                        transitionDuration: `${ canvas.can3.trans ? '' : '0s' }`,
                    }}
                />
    
                <div className="Modal-User-Interface-Wrapper">
                    <div className="Information-Box">
                        <h4>{ `${ state.counter }/${ mediaJSON.length }` }</h4>
                    </div>
                    <Anchor
                        altClass="icon"
                        fileName="cross.svg"
                        style={{ position: 'absolute', top: '0', right: '0', opacity: '.5' }}
                        clicked={ handleClose }
                    />
                    <Anchor
                        altClass="icon"
                        fileName="arrow.svg"
                        style={{ transform: 'rotate(180deg)' }}
                        clicked={ ()=>content.prev() }
                    />
                    <Anchor
                        altClass="icon"
                        fileName="arrow.svg"
                        clicked={ ()=>content.next() }
                    />
                </div>
            </div>
        );
    }
    
    export default MediaViewer;
    

    和 CSS

    .Media-Viewer {
        display: flex;
        position: fixed;
        justify-content: space-around;
        align-items: center;
        height: calc(100*var(--vh));
        width: 100vw;
        height: 100vh;
        top: 0; left: 0;
        overflow: hidden;
        z-index: 10;
    
        transition: opacity .4s ease;
    }
    .Media-Viewer.hide,
    .Media-Viewer.show {
        opacity: 0;
    }
    .Media-Viewer.hidden {
        display: none;
    }
    
    
    .Media-Viewer-Content {
        display: flex;
        position: absolute;
        height: 100%;
        width: 100%;
        object-fit: contain;
        top: 0; left: 0;
        z-index: 9;
        transition: transform .4s ease;
    
        will-change: transform;
    }
    .Media-Viewer-Content.center {
        transform: translate3d(0,0,0);
    }
    .Media-Viewer-Content.right {
        transform: translate3d(100vw,0,0);
    }
    .Media-Viewer-Content.left {
        transform: translate3d(-100vw,0,0);
    }
    
    
    .Modal-User-Interface-Wrapper {
        display: flex;
        position: relative;
        justify-content: space-between;
        align-items: center;
        width: calc( 100vw - (100vw - 300px) / 10 );
        opacity: .6;
        height: calc(100*var(--vh));
        z-index: 10;
        transition: opacity 1.2s ease;
        transition-delay: 4s;
    }
    
    
    .Media-Viewer .Anchor {
        display: flex;
        position: relative;
        height: 3.5rem;
        width: 3.5rem;
        padding: 1rem .7rem 1rem 1rem;
        opacity: .1;
        margin-bottom: 1.7rem;
        border-radius: 4rem;
        cursor: pointer;
        transition: opacity, background-color .7s ease;
        z-index: 10;
        transition-duration: .44s;
    }
    
    .Media-Viewer .Anchor:hover,
    .Media-Viewer:active .Modal-User-Interface-Wrapper,
    .Media-Viewer-Content:active .Modal-User-Interface-Wrapper {
        opacity: .9;
        transition-duration: .1s;
        transition-delay: 0s;
    }
    .Media-Viewer .Anchor:hover {
        opacity: .7;
        background-color:rgba(0, 0, 0, 0.089);
    }
    
    
    /* overlay */
    .Media-Viewer::before {
        content: '';
        position: absolute;
        height: 100vh;
        width: 100vw;
        top: 0;
        z-index: 8;
        background-color: rgba(0, 0, 0, 0.932);
        backdrop-filter: blur(7px);
        -webkit-backdrop-filter: blur(10px);
        z-index: -1;
    }
    
    
    
    .Information-Box {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: .4rem; right: 0; left: 0;
        margin: 0 auto;
        height: 2.7rem;
        width: calc(3rem + 10vw);
        background: rgb(220,148,87);
        background: linear-gradient(133deg, rgba(32, 28, 24, 0.719) 0%, rgba(43, 32, 26, 0.582) 100%);
        border-radius: .6rem;
    
        z-index: 10;
    }
    
    .Information-Box h4 {
        position: absolute;
        color: #fff;
        font-size: .85rem;
        font-weight: 700;
        text-shadow: 1px 2px 5px rgb(1, 4, 5);
    }
    

    也许你会在这里找到有用的东西..

    【讨论】:

    • 否则,如果你想平滑滚动到一边..用flex-direction: row动画transform: translateX将它们并排堆叠并使用'intersectionObserver'触发播放..
    • 你能给我确切的代码吗,因为我在实现上述代码时遇到了一些困难
    • 有什么解决办法?连续水平滚动还是无限下一个/上一个切换?
    猜你喜欢
    • 1970-01-01
    • 2014-12-27
    • 1970-01-01
    • 2021-09-07
    • 2021-03-21
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多