Reactjs 如何在NextJS中创建旋转木马?

Reactjs 如何在NextJS中创建旋转木马?,reactjs,carousel,next.js,react-bootstrap,Reactjs,Carousel,Next.js,React Bootstrap,我正试图建立一个旋转木马就像它是如何在亚马逊主页上。我用React引导用于旋转木马,但它似乎不起作用。它只是像在一列中一样堆叠每个项目 <Carousel> <Carousel.Item> <img src={'https://images-na.ssl-images-amazon.com/images/G/01/AmazonExports/Fuji/2020/October/Fuji_Tall

我正试图建立一个旋转木马就像它是如何在亚马逊主页上。我用React引导用于旋转木马,但它似乎不起作用。它只是像在一列中一样堆叠每个项目

<Carousel>
                <Carousel.Item>
                    <img src={'https://images-na.ssl-images-amazon.com/images/G/01/AmazonExports/Fuji/2020/October/Fuji_Tallhero_Dash_en_US_1x._CB418727898_.jpg'} alt="" />
                </Carousel.Item>

                <Carousel.Item>
                    <img src={'https://images-na.ssl-images-amazon.com/images/G/01/AmazonExports/Events/2020/PrimeDay/Fuji_TallHero_NonPrime_v2_en_US_1x._CB403670067_.jpg'} alt="" />
                </Carousel.Item>
            </Carousel>


答案中接受使用React Bootstrap以外的任何其他框架编写的代码。

您可以通过将css代码添加到样式资产文件(如.cssscss)来设置按钮的样式

/* class="carousel slide" */
.carousel-control-next {
  /* Find your correct z-index value */
  z-index: 1
}

.carousel-control-prev {
  /* Find your correct z-index value */
  z-index: 1
}

同样,您也可以通过添加自定义样式来自定义这些按钮。

我刚刚为客户(牙医)在大约一个小时内完成了一个项目。将其用于患者证明。还不错,vercel在将繁重的工作隔离到单个components子目录方面做得很好

import { useKeenSlider } from 'keen-slider/react';
import React, {
    Children,
    FC,
    isValidElement,
    useState,
    useEffect,
    useRef
} from 'react';
import cn from 'classnames';
import css from './keen-slider.module.css';

const KeenSlider: FC = ({ children }) => {
    const [currentSlide, setCurrentSlide] = useState(0);
    const [isMounted, setIsMounted] = useState(false);
    const sliderContainerRef = useRef<HTMLDivElement>(null);
    const [ref, slider] = useKeenSlider<HTMLDivElement>({
        loop: true,
        slidesPerView: 1,
        mounted: () => setIsMounted(true),
        slideChanged(s) {
            setCurrentSlide(s.details().relativeSlide);
        }
    });
    // Stop the history navigation gesture on touch devices
    useEffect(() => {
        const preventNavigation = (event: TouchEvent) => {
            // Center point of the touch area
            const touchXPosition = event.touches[0].pageX;
            // Size of the touch area
            const touchXRadius = event.touches[0].radiusX || 0;
            // We set a threshold (10px) on both sizes of the screen,
            // if the touch area overlaps with the screen edges
            // it's likely to trigger the navigation. We prevent the
            // touchstart event in that case.
            if (
                touchXPosition - touchXRadius < 10 ||
                touchXPosition + touchXRadius > window.innerWidth - 10
            )
                event.preventDefault();
        };
        sliderContainerRef.current!.addEventListener('touchstart', preventNavigation);
        return () => {
            sliderContainerRef.current!.removeEventListener(
                'touchstart',
                preventNavigation
            );
        };
    }, []);

    return (
        <div className={css.root} ref={sliderContainerRef}>
            <button
                className={cn(css.leftControl, css.control)}
                onClick={slider?.prev}
                aria-label='Previous Testimonial'
            />
            <button
                className={cn(css.rightControl, css.control)}
                onClick={slider?.next}
                aria-label='Next Testimonial'
            />
            <div
                ref={ref}
                className='keen-slider h-full transition-opacity duration-150'
                style={{ opacity: isMounted ? 1 : 0 }}
            >
                {Children.map(children, child => {
                    // Add the keen-slider__slide className to children
                    if (isValidElement(child)) {
                        return {
                            ...child,
                            props: {
                                ...child.props,
                                className: `${
                                    child.props.className ? `${child.props.className} ` : ''
                                }keen-slider__slide`
                            }
                        };
                    }
                    return child;
                })}
            </div>
            {slider && (
                <div className={cn(css.positionIndicatorsContainer)} ref={ref}>
                    {[...Array(slider.details().size).keys()].map(idx => {
                        return (
                            <button
                                aria-label='Position indicator'
                                key={idx}
                                className={cn(css.positionIndicator + `keen-slider__slide`, {
                                    [css.positionIndicatorActive]: currentSlide === idx
                                })}
                                onClick={() => {
                                    slider.moveToSlideRelative(idx);
                                }}
                            >
                                <div className={css.dot} />
                            </button>
                        );
                    })}
                </div>
            )}
        </div>
    );
};

export default KeenSlider;

我的实现

import cn from 'classnames';
import { Container } from '@components/UI';
import TestimonialsData from './TestimonialsData';
import TestimonialsWrapper from './TestimonialsWrapper';
import dynamic from 'next/dynamic';
import { ALL_TESTIMONIALS } from '@lib/graphql';
import { useQuery } from '@apollo/client';
import {
    PostObjectsConnectionOrderbyEnum,
    OrderEnum
} from '@_types/graphql-global-types';
import {
    AllTestimonials,
    AllTestimonialsVariables
} from '@lib/graphql/AllTestimonials/__generated__/AllTestimonials';
import css from './testimonials.module.css';
import KeenSlider from '../KeenSlider/keen-slider';

export const TestimonialsQueryVars: AllTestimonialsVariables = {
    first: 10,
    order: OrderEnum.ASC,
    field: PostObjectsConnectionOrderbyEnum.TITLE
};

const LoadingDots = dynamic(() => import('@components/UI/LoadingDots'));

const Loading = () => (
    <div className='w-80 h-80 flex items-center text-center justify-center p-3'>
        <LoadingDots />
    </div>
);

const dynamicProps = {
    loading: () => <Loading />
};

const ApolloErrorMessage = dynamic(
    () => import('@components/ErrorMessage'),
    dynamicProps
);

const TestimonialsCoalesced = () => {
    const { loading, error, data } = useQuery<
        AllTestimonials,
        AllTestimonialsVariables
    >(ALL_TESTIMONIALS, {
        variables: TestimonialsQueryVars,
        notifyOnNetworkStatusChange: true
    });

    return error ? (
        <>
            <ApolloErrorMessage
                message={`${error.message}`}
                graphQLErrors={error.graphQLErrors}
                networkError={error.networkError}
                extraInfo={error.extraInfo}
                stack={error.stack}
                name={error.name}
            />
        </>
    ) : loading && !error ? (
        <Loading />
    ) : (
        <Container className={cn('mx-auto max-w-none w-full')} clean>
            {data &&
            data.prosites !== null &&
            data.prosites.edges !== null &&
            data.prosites.edges.length > 0 ? (
                <TestimonialsWrapper root={css.sliderContainer}>
                    <KeenSlider>
                        {data.prosites.edges.map(edge => {
                            return edge !== null && edge.cursor !== null && edge.node !== null ? (
                                <div className={css.childContainer}>
                                    <TestimonialsData
                                        root={''}
                                        key={edge.node.id}
                                        id={edge.node.id}
                                        __typename={edge.node.__typename}
                                        title={edge.node.title}
                                        slug={edge.node.slug}
                                        featuredImage={edge.node.featuredImage}
                                        content={edge.node.content}
                                        modified={edge.node.modified}
                                    />
                                </div>
                            ) : (
                                <div>{error}</div>
                            );
                        })}
                    </KeenSlider>
                </TestimonialsWrapper>
            ) : (
                <div>{error}</div>
            )}
        </Container>
    );
};

export default TestimonialsCoalesced;


嗯@Kal它可以工作,但是按钮在我的内容后面,我想把它的z索引设置得更高一点,我还想定制这些按钮。你能用这个写一个答案吗?