customPaging 옵션을 이용한 작업방식입니다.

슬라이드 2개로 페이징을 구현하려면 새로 작성한 글을 참고해주세요!

 

 


 

 

사진첩 작업을 하기위해 react-slick 라이브러리를 활용해보겠습니다.

그냥 slick을 쓴 경험은 있지만 react에서는 강의를 보고 예제 코드 만들어 본 이후 처음이네요.ㅎㅎ

 

 

라이브러리 설치를 먼저 해주시구요.

npm i react-slick

 

 

대충 테스트해보기위해 slick 사이트에 있는 예제를 가져와서 간단히 뚝딱 만들어보겠습니다.

아래 사이트에서 docs를 확인해보세요.

https://react-slick.neostack.com/

 

Neostack

The last react carousel you will ever need

react-slick.neostack.com

 

 

예제코드

확인할때 눈에 보기 쉽게 div에 background를 추가해보았습니다.

import React from 'react';
import Slick from 'react-slick';
import styled from 'styled-components';

const Div = styled.div`
    width: 100%;
    height: 50px;
    background: red;
`;

const Test = () => {
    return (
        <Slick
            dots={true}
            infinite
            speed={500}
            slidesToShow={1}
            slidesToScroll={1}
        >
          <Div>
            <h3>1</h3>
          </Div>
          <Div>
            <h3>2</h3>
          </Div>
          <Div>
            <h3>3</h3>
          </Div>
          <Div>
            <h3>4</h3>
          </Div>
          <Div>
            <h3>5</h3>
          </Div>
          <Div>
            <h3>6</h3>
          </Div>
        </Slick>
    );
};

export default Test;

 

 

그 후 결과물을 보고 당황했습니다;

아래처럼 정상적으로 나오지 않더군요.

뭐가 문제냐..

예시 코드 결과물

 

 

음.. 스타일을 수정해주면 됩니다.

객체들이 정렬될 수 있게 display를 수정해줍니다.

이 상태에서 slick이 부여한 스타일을 덮여씌우려면 글로벌 스타일을 통해 작업이 필요할 것 같습니다.

styled-components에서 제공하는 createGlobalStyle를 이용해서 스타일을 작성해줍니다.

그리고 이 Global 컴포넌트를 사용하면 됩니다.

import styled, { createGlobalStyle } from 'styled-components';

const Global = createGlobalStyle`
  .slick-slide {
	  display: inline-block;
  }
`;

 

 

정상적으로 보이네요.

뭐 지금도 1 다음에 2가 보이긴 하지만요;

저것도 스타일로 해결 가능합니다.

수정된 예시 코드 결과물

 

 

여튼,

간단히 예제코드를 확인했으니 어떻게 하면 되는지 머리에 좀 그려졌습니다.

이제 원하는 슬라이드로 만들기 위해 스타일이나 react-slick의 속성을 사용해 코드를 작성해보겠습니다.

설명은 주석을 통해 작성하겠습니다. 연관된 설명은 번호가 동일합니다.

import React, { useRef } from 'react';
import Slick from 'react-slick';
import styled, { css } from 'styled-components';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';

const Wrap = styled.div`
    position: relative;
    padding-bottom: 70px;
    overflow: hidden;
	
    // 1. Global style 추가했던 것을 슬라이드 상단에 Wrap을 만들어 여기서 선언했습니다.
    .slick-slide {
        display: inline-block;
    }
	
    // 2. 제가 추가한 커스텀 클래스입니다.
    // pagination 부분입니다.
    .slick-dots.slick-thumb {
        position: absolute;
        bottom: 0;
        left: 50%;
        padding: 0;
        margin: 0;
        list-style: none;
        transform: translate(-50%);

        li {
            position: relative;
            display: inline-block;
			
            &.slick-active {
                span {
                    filter: none;
                }
            }
        }
    }  
`;

const SlickItems = styled.div`
    width: 100%;    
    height: 400px;
    text-align: center;

    img {
        max-width: 100%;
        height: 100%;
        vertical-align: top;
    }
`;

const defaultButtonStyle = css`
    position: absolute;
    top: calc(50% - 50px);
    padding: 0;
    width: 30px;
    height: 30px;
    line-height: 1;
    border: none;
    border-radius: 50%;
    background: none;
    outline: none;
    cursor: pointer;
`;

const PrevButton = styled.button`
    ${defaultButtonStyle}
    left: 0;
`;

const NextButton = styled.button`
    ${defaultButtonStyle}
    right: 0;
`;

const defaultIconStyle = css`
    font-size: 22px;
    color: #dedede;

    &:focus,
    &:hover {
        color: #666;
    }
`;

const PrevIcon = styled(LeftOutlined)`
    ${defaultIconStyle}
`;

const NextIcon = styled(RightOutlined)`
    ${defaultIconStyle}
`;

const PagingAnchor = styled.a`
    display: block;
    width: 50px;
    height: 50px;

    img {
        width: 100%;
        height: 100%;
    }
`;

// 3. custom pagination을 만듭니다.
// background를 통해 이미지를 넣어줍니다.
// filter를 통해 흑백으로 보이게 하고 active가 되면 흑백을 제거합니다. (31라인참고)
const Paging = styled.span`
    display: inline-block;
    width: 100%;
    height: 100%;
    vertical-align: middle;
    background: url(${props => props.src})no-repeat;
    background-size: 100% 100%;
    filter: grayscale(1);
`;

// 4. 샘플이미지
const images = [
    {
        src: "https://www.artinsight.co.kr/data/tmp/1910/20191029212614_fawslbwd.jpg",
        title: "1"
    },
    {
        src: "https://www.artinsight.co.kr/data/tmp/1910/20191029212649_esiekzxf.jpg",
        title: "2"
    },
    {
        src: "https://www.artinsight.co.kr/data/tmp/1910/20191029212707_zcrkccgp.jpg",
        title: "3"
    },
    {
        src: "https://www.artinsight.co.kr/data/tmp/1910/20191029212724_pacwfbiz.jpg",
        title: "4"
    },
];

const Slide = () => {
	
    // 5. custom arrows를 만들어 ref를 통해 제어합니다.
    const slickRef = useRef(null);

	// 6. slick에 추가할 세팅입니다.
    const settings = {
        dots: true,
        
        // 2. 제가 추가한 커스텀 클래스입니다. (pagination)
        dotsClass: "slick-dots slick-thumb",
        
        // 5. custom arrows를 만들기 위해 기본 arrows옵션을 false로 합니다.
        arrows: false,
        infinite: true,
        slidesToShow: 1,
        slidesToScroll: 1,
        
        // 2. custom pagination을 만듭니다.
        // i(index)를 통해 샘플이미지에서 동일한 이미지를 가져옵니다.
        customPaging: function(i) {
            const imgSrc = images[i].src;
            return (
                <PagingAnchor>
                    <Paging src={imgSrc} />
                </PagingAnchor>
            );
        },
    };
    
	// 5. custom arrows 동작 함수를 만듭니다.
    const previous = useCallback(() => slickRef.current.slickPrev(), []);
    const next = useCallback(() => slickRef.current.slickNext(), []);

    return (
        <Wrap>
			
			// 5.6.
            // custom arrows를 위해 ref를 설정합니다.
            // 세팅을 넣어줍니다. (공식문서 docs참고)
			<Slick ref={slickRef} {...settings}>
            	
                // 4. 샘플이미지로 반복문을 돌려 슬라이드 아이템을 렌더합니다.
                {images.map((v, i) => {
                    return (
                        <SlickItems key={`${v.title}_${i}`}>
                            <img src={v.src} />
                        </SlickItems>
                    )
                })}
            </Slick>
			
            // 5. custom arrows입니다.
            <>
                <PrevButton onClick={previous}>
                    <PrevIcon />
                    <span className="hidden">이전</span>
                </PrevButton>

                <NextButton onClick={next}>
                    <NextIcon />
                    <span className="hidden">다음</span>
                </NextButton>
            </>
        </Wrap>
    );
};

export default Slide;

이미지 출처는 https://www.artinsight.co.kr/인 것 같습니다. 사실 뉴스 검색해서 사용한 이미지인데, 주소가 저기로 되어있습니다. 문제가되면 수정하겠습니다.

 

 

결과물입니다.

코드 완성 결과물

 

 

아직 간단히 만든 상태라 버그가 존재합니다.

예를들어.. 이미지 개수가 왕창 늘어나면? 아래 pagination은 깨질 것입니다.

그것 말고도 만지다보면 많이 있겠죠.

저는 딱 정해진 갯수의 사진만 쓸거기에 수정하지 않겠지만, 동적으로 이미지 갯수가 달라진다면 수정해야합니다.

 

 

gif

코드 완성 결과물 gif

용량때문에 급하게 누르느라 gif가 엄청빠르네요;;;

 

 

이번시간에 만든 슬라이드는 

화살표, 페이지 번호를 사용자 요구조건으로 수정하는 기능만 적용했습니다.

간단합니다. 

하지만 이 기능 구현하면서 docs를 읽어봤는데, 대부분의 기능은 docs를 보면 만들 수 있을 것 같습니다.(우와)

 

 

 

bug

antd 라이브러리의 card 컴포넌트와 slick을 같이 사용한다면, 버그가 생깁니다.

버그를 해결하기 위해 global에 스타일 하나를 수정해줘야합니다. 

꼭 global일 필요는 없으나 .ant-card-cover를 감싸고 있는 element면 됩니다.

글로벌 스타일 적용방법참고해서 아래 코드를 추가해주세요. 

const Global = createGlobalStyle`
  .ant-card-cover {
	  transform: none !important;
  }
`;

 

 

+ Recent posts