React Slick 설치

npm i react-slick

아래의 css 도 설치해 줍니다.

npm install slick-carousel

기본 Slider 생성

css 를 불러와야합니다.

import React from "react";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";

export default function SimpleSlider() {
  var settings = {
    dots: true,
    infinite: true,
    speed: 500,
    slidesToShow: 1,
    slidesToScroll: 1
  };
  return (
    <Slider {...settings}>
      <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>
    </Slider>
  );
}

현재 선택된 슬라이드 index 값 가져오기

useState를 활용하여 현재 슬라이드의 index를 넣어줍니다.

react-slick의 api문서의 beforeChange를 통해 받아올 수 있습니다.

beforeChange
Type: func
Default: null
Description: Index change callback. `(oldIndex, newIndex) => ...`
 const [slideIndex, setSlideIndex] = useState(0);
  const settings = {
    dots: true,
    infinite: true,
    speed: 500,
    slidesToShow: 1,
    slidesToScroll: 1
    beforeChange: (current, next) => {
      return setSlideIndex(current);
    },
  };

슬라이드 컴포넌트별로 현재 선택된 슬라이드인지 비교합니다.

슬라이드는 0부터 시작합니다.

<Slider {...settings}>
      <Slide border={0==slideIndex}>
        <h3>1</h3>
      </div>
      <Slide border={1==slideIndex}>
        <h3>2</h3>
      </div>
      <Slide border={2==slideIndex}>
        <h3>3</h3>
      </div>
      <Slide border={3==slideIndex}>
        <h3>4</h3>
      </div>
      <Slide border={4==slideIndex}>
        <h3>5</h3>
      </div>
      <Slide border={5==slideIndex}>
        <h3>6</h3>
      </div>
    </Slider>

현재 선택된 슬라이드가 맞으면 true 아니면 false를 porps.border로 전달해줍니다.

전달 받은 props.border가 true 이면 빨간색 테두리 아니면 none으로 스타일링 해줍니다.

const Slide = styled.div`
	border:${(props)=> (props.border ? "1px solid red" : "none")}
`;

 

728x90

2021.03.21 - [Usage/ReactJS] - Table of Contents 스크롤 메뉴 구현

 

Table of Contents 스크롤 메뉴 구현

createContext를 사용하여 provider, context 생성 Toc.js 생성 메뉴에서 이동 시킬 위치를 각각의 컴포넌트에서 pos로 받아와서 저장 시킬 예정 import React from "react"; import { createContext, useState }..

mugon-devlog.tistory.com

이전 포스트의 확장판입니다.

ToC 스크롤 메뉴가 구현되어 있다는 가정하에 시작하겠습니다.

스크롤의 현재 위치, 동적으로 구현하고픈 페이지의 상단과 하단 위치의 절대 값

//현재 위치가 이곳에 왔을때 active true
const [active, setActive] = useState(false);
const element = useRef(null);

useEffect(() => {
  const onScroll = () => {
    const scrollTop = window.pageYOffset + 100; //현재 위치
    //현재 페이지 상단
    const pagePosTop =
    element.current.getBoundingClientRect().top + window.pageYOffset;
    //현재 페이지 하단
    const pagePosBot =
    element.current.getBoundingClientRect().bottom + window.pageYOffset;
    if (pagePosTop < scrollTop && scrollTop < pagePosBot) {
      setActive(true);
    } else {
      setActive(false);
    }
  };
  if (loc !== 0) {
  	window.addEventListener("scroll", onScroll);
  }
  return () => {
  	window.removeEventListener("scroll", onScroll);
  };
}, [active]);

-------
return(
 <Page id="fourth" ref={element}>
 {* *}
 </Page>
)

스크롤이 페이지 영역에 들어왔을때 나타나게끔 css

styled-components를 이용해 active값을 받아 구현

const IconStyle = styled.img`
  width: 40rem;
  height: 15rem;
  animation: ${(props) => (props.active ? "fadein 3s" : "fadeout 3s")};
  @keyframes fadein {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
  @keyframes fadeout {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }
`;
--------
return (
	<IconStyle src="./icon.png" active={active} />
);

 

 

728x90

createContext를 사용하여 provider, context 생성

Toc.js 생성

메뉴에서 이동 시킬 위치를 각각의 컴포넌트에서 pos로 받아와서 저장 시킬 예정

import React from "react";
import { createContext, useState } from "react";

const ToCContext = createContext([{}, () => {}]);
const TocProvider = ({ children }) => {
  const [pos, setPos] = useState({
    First: 0,
    Second: 0,
    Third: 0,
    Fourth: 0,
  });

  return (
    <ToCContext.Provider value={[pos, setPos]}>{children}</ToCContext.Provider>
  );
};
const { Consumer: ToCConsumer } = ToCContext;
export { TocProvider, ToCConsumer };
export default ToCContext;

페이지의 위치 pos에 저장시키기

먼저, context를 사용하려는 컴포넌트 바깥에서 Provider로 감싸준다.

import logo from "./logo.svg";
import "./App.css";
import Nav from "./Nav";
import First from "./First";
import Second from "./Second";
import Third from "./Third";
import Fourth from "./Fourth";
import { TocProvider } from "./Toc";
import styled from "styled-components";
const BodyStyle = styled.div``;
function App() {
  return (
    <div className="App">
      <TocProvider>
        <Nav />
        <BodyStyle>
          <First />
          <Second />
          <Third />
          <Fourth />
        </BodyStyle>
      </TocProvider>
    </div>
  );
}

export default App;

 

ToC.js에서 생성한 ToCContext의 pos를 useContext로 불러옴

useRef를 이용해서 컴포넌트 First의 ref값을 가져옴

해당 컴포넌트의 절대값을 구하기위해  Viewport의 시작지점을 기준으로 한 상대 좌표인 element.getBoundingClientRect(). top과 window.pageYOffset 전체 페이지에서 얼만큼 scroll 됐는지 픽셀 단위를 알려주는 값을 더 함

import React, { useContext, useEffect, useRef } from "react";
import styled from "styled-components";
import ToCContext from "./Toc";
const FirstStyle = styled.div`
  width: 100%;
  height: 500px;
  background-color: green;
`;
function First() {
  const element = useRef(null);
  const [pos, setPos] = useContext(ToCContext);
  useEffect(() => {
    const rect = element.current.getBoundingClientRect();
    setPos((pos) => ({
      ...pos,
      [element.current.id]: rect.top + window.pageYOffset,
    }));
  }, [setPos]);
  return (
    <FirstStyle id="First" ref={element}>
      first
    </FirstStyle>
  );
}

export default First;

네비게이션 구현

useEffect로 현재 스크롤 위치가 메뉴에 해당하는 컴포넌트 영역에 들어왔는지 체크 하고 들어오면 메뉴 폰트에 bold를 줌

import React, { useContext, useEffect, useState } from "react";
import styled from "styled-components";
import ToCContext from "../../../components/ToC";

const NavFont = styled.a`
  font-family: Noto Sans KR;
  font-weight: ${(props) => props.active};
  font-size: 2.2rem;
  color: #ffffff;
  line-height: 3.2rem;
  text-decoration: none;
`;
function Header({
  list = [
    {
      name: "First",
      href: "First",
    },
    {
      name: "Second",
      href: "Second",
    },
    {
      name: "Third",
      href: "Third",
    },
    {
      name: "Fourth",
      href: "Fourth",
    },
  ],
}) {
  const [active, setActive] = useState(0);
  const [pos] = useContext(ToCContext);

  useEffect(() => {
    const onScroll = () => {
      const scrollTop = window.pageYOffset;
      if (scrollTop < pos.Second) {
        setActive(0);
      }
      if (pos.Second <= scrollTop && scrollTop < pos.Third) {
        setActive(1);
      }
      if (pos.Third <= scrollTop && scrollTop < pos.Fourth) {
        setActive(2);
      }
      if (pos.Fourth <= scrollTop) {
        setActive(3);
      }
    };
    if (pos.Second !== 0 && pos.Thrid !== 0 && pos.Fourth !== 0) {
      window.addEventListener("scroll", onScroll);
    }
    console.log("active", active);
    return () => {
      window.removeEventListener("scroll", onScroll);
    };
  }, [pos]);

  return (
    <Box>
      <NavBox>
        {list.map((el, idx) => (
          <NavFont
          key={idx}
          href={`#${el.href}`}
          active={idx === active ? "bold" : "regular"}
          >
          {el.name}
          </NavFont>
        ))}
      </NavBox>
    </Box>
  );
}

export default Header;
728x90

메뉴를 눌렀을때 선택된 메뉴에 bold와 underline을 주며 하단 내용을 바꿈

Tab 메뉴의 항목별로 나타낼 항목 정의

const TabUI = {
    1: (
      <TabContentsBoxStyle>
        <TabContentsTextStyle>
          단 한번의 입력으로 자동 작성되는 나만의 낚시 장비 세트
        </TabContentsTextStyle>
        <TabContentsImageStyle src="./assets/my_img1@3x.png"></TabContentsImageStyle>
      </TabContentsBoxStyle>
    ),
    2: (
      <TabContentsBoxStyle>
        <TabContentsTextStyle>
          지역 및 어종으로 나눠서 보는 나만의 낚시 포인트, 어보서비스!
        </TabContentsTextStyle>
        <TabContentsImageStyle src="./assets/my_img2@3x.png"></TabContentsImageStyle>
      </TabContentsBoxStyle>
    ),
  };

Tab 메뉴를 클릭했을때의 이벤트 정의

1. 어떤 메뉴를 클릭했는지

2. 클릭했을때, 클릭 안했을때

3. 클릭 함수

//어떤 버튼을 선택했는지
const [selected, setSelected] = useState(1);
//버튼을 선택했을때 true로 줘서 활성상태로 바꾸기, 클릭 안했을땐 false
const [rightActive, setRightActive] = useState(false);
//기본으로 보여줄 항목은 true
const [leftActive, setLeftActive] = useState(true);
//버튼 이벤트 정의
function selectMenu(props) {
if (props === 1) {
  setSelected(1);
  setLeftActive(true);
  setRightActive(false);
} else if (props === 2) {
  setSelected(2);
  setLeftActive(false);
  setRightActive(true);
}

스타일 컴포넌트에 props 전달해서 css 동적으로 변화

const TabLeftButtonStyle = styled.div`
 font-weight: ${(props)=>props.leftActive ? bold : regular};
 font-decoration : ${(props)=>props.leftActive ? underline : none};
`;

function Tab() {
  const [rightActive, setRightActive] = useState(false);
  const [leftActive, setLeftActive] = useState(true);
  }
    return (
        <TabNavStyle>
			//Tab 버튼
          <TabLeftButtonStyle
            onClick={() => selectMenu(1)}
            //아래와 같이 정의하면 styled에 props로 전달 가능
            leftActive={leftActive}
          >
            나의 낚시 장비
          </TabLeftButtonStyle>         
        </TabNavStyle>
    )
}

export default Tab

전체 코드

const TabLeftButtonStyle = styled.div`
 font-weight: ${(props)=>props.leftActive ? bold : regular};
 font-decoration : ${(props)=>props.leftActive ? underline : none};
`;
const TabRightButtonStyle = styled.div`
 font-weight: ${(props)=>props.RightActive ? bold : regular};
 font-decoration : ${(props)=>props.RightActive ? underline : none};
`;
// tab 메뉴의 버튼 눌렀을때 나타날 컴포넌트 정의
const TabUI = {
    1: (
      <TabContentsBoxStyle>
        <TabContentsTextStyle>
          단 한번의 입력으로 자동 작성되는 나만의 낚시 장비 세트
        </TabContentsTextStyle>
        <TabContentsImageStyle src="./assets/my_img1@3x.png"></TabContentsImageStyle>
      </TabContentsBoxStyle>
    ),
    2: (
      <TabContentsBoxStyle>
        <TabContentsTextStyle>
          지역 및 어종으로 나눠서 보는 나만의 낚시 포인트, 어보서비스!
        </TabContentsTextStyle>
        <TabContentsImageStyle src="./assets/my_img2@3x.png"></TabContentsImageStyle>
      </TabContentsBoxStyle>
    ),
  };
function Tab() {
	//어떤 버튼을 선택했는지
  const [selected, setSelected] = useState(1);
	//버튼을 선택했을때 true로 줘서 활성상태로 바꾸기, 클릭 안했을땐 false
  const [rightActive, setRightActive] = useState(false);
  const [leftActive, setLeftActive] = useState(true);
	//버튼 이벤트 정의
  function selectMenu(props) {
    if (props === 1) {
      setSelected(1);
      setLeftActive(true);
      setRightActive(false);
    } else if (props === 2) {
      setSelected(2);
      setLeftActive(false);
      setRightActive(true);
    }
  }
    return (
        <TabNavStyle>
				//Tab 버튼
          <TabLeftButtonStyle
            onClick={() => selectMenu(1)}
            leftActive={leftActive}
          >
            나의 낚시 장비
          </TabLeftButtonStyle>
          <TabRightButtonStyle
            onClick={() => selectMenu(2)}
            rightActive={rightActive}
          >
            나의 어보
          </TabRightButtonStyle>
        </TabNavStyle>
		//선택된 버튼에 따라 그려지는 컴포넌트
        {TabUI[selected]}
    )
}

export default Tab
728x90

+ Recent posts