티스토리 뷰

안녕하세요. 좋아요요정입니다! 

2021년이 일주일 남았네요. :) 얌전히 포트폴리오 준비하기 좋은 겨울.. 오늘은 react로 사이드바 구현하는 방법을 작성합니다.

 

 

 

 

완성본 영상💕

컴포넌트 기능

1. <Sidebar> {내용 직접 작성 혹은 내용이 들어간 컴포넌트} </Sidebar >로 컴포넌트는 따로, 내용 따로 가능합니다. 

2. Sidebar 컴포넌트의 width값 변경이 가능합니다. 
3. 사이드바가 오픈되어있을 때 외부를 클릭하면 사이드바가 닫히는 기능이 추가되어 있습니다.

 

 

 

 

 

<Sidebar> 컴포넌트 코드

import React, {useEffect, useRef, useState } from "react";
import styles from "./sidebar.module.css";


const Sidebar = ({ width=280, children }) => {
  const [isOpen, setOpen] = useState(false);
  const [xPosition, setX] = useState(-width);
  const side = useRef();
  
  // button 클릭 시 토글
  const toggleMenu = () => {
    if (xPosition < 0) {
      setX(0);
      setOpen(true);
    } else {
      setX(-width);
      setOpen(false);
    }
  };
  
  // 사이드바 외부 클릭시 닫히는 함수
  const handleClose = async e => {
    let sideArea = side.current;
    let sideCildren = side.current.contains(e.target);
    if (isOpen && (!sideArea || !sideCildren)) {
      await setX(-width); 
      await setOpen(false);
    }
  }

  useEffect(()=> {
    window.addEventListener('click', handleClose);
    return () => {
      window.removeEventListener('click', handleClose);
    };
  })


  return (
    <div className={styles.container}>
      <div ref={side}  className={styles.sidebar} style={{ width: `${width}px`, height: '100%',  transform: `translatex(${-xPosition}px)`}}>
          <button onClick={() => toggleMenu()}
          className={styles.button} >
            {isOpen ? 
            <span>X</span> : <img src="images/avatar.png" alr="contact open button" className={styles.openBtn}/>
            }
          </button>
        <div className={styles.content}>{children}</div> //사이드바 컴포넌트 내부 값이 구현되는 위치
      </div>
    </div>
  );
};


export default Sidebar;

1.  props 매개변수의 width에 기본값 280을 설정해둠으로써 오류를 일차 방지합니다.

2. 외부 클릭시 닫히는 함수를 원하지 않는다면  handleClose, useEffect(()=> {widow.addEventListener..}) 두 부분을 삭제하고 사용하시면 됩니다.

3. 컴포넌트가 사용되는 위치에서 자식요소로 들어가있던 데이터가 {children} 위치로 구현됩니다. 

 

 

 

 

현재 등록되어있는 sidebar.module.css 

.container {
  background-color: #E3ECF1;
}
.sidebar {
  background-color: #E3ECF1;
  border-left: 4px solid #202020;
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  transition: 0.4s ease;
  color: #202020;
  height: 100%;
  z-index: 99;
}
.button {
  position: relative;
  left: -50px;
  top: 10px;
  width: 40px;
  height: 40px;
  z-index: 99;
  transition: 0.8s ease;
  border: 2px solid #202020;
  border-radius: 40px;
  overflow: hidden;
}
.openBtn {
  width: 100%;
  height: 100%;
}
.content {
  padding: 40px 40px 0 20px;
  position: relative;
  width: 100%;
}
.icon {
  margin: 0;
  color: #202020;
}

1. position :fixed; 값은 필수로 적용되어 있어야 브라우저에 붙는 기능이 정상 작동합니다 :) 

그 외 수정하실 부분은 수정하시고 사용하시면 돼요.

 

 

 

사용하는 위치 예시

import React,{ useState } from 'react';
import styles from './header.module.css';
import Sidebar from '../components/sidebar/sidebar';
import Contact from 'pages/contact/contact';

const Header = (props) => {
  return (
    <div className={styles.container}>
      <nav>
        <ul className={styles.nav}>
          <li className={styles.home}>home</li>
          <li className={styles.project}>project</li>
        </ul>
      </nav>
      <Sidebar width={320}> //원하는 width사이즈
        <Contact />
      </Sidebar>
    </div>
    )
};

export default Header;

1. 원하는 width사이즈를  props로 전달할 수 있습니다.

2. 컴포넌트를 사용할 위치에서  import 해주신 후  <Sidebar> {내용 직접 작성 혹은 내용이 들어간 컴포넌트} </Sidebar > 로 작성해주시면 내부 데이터가 사이드바 안에 위치합니다. 

 

 

 

 

 

 

left에 위치시키고 싶다면? 

<Sidebar> 컴포넌트 코드

import React, {useEffect, useRef, useState} from "react";
import styles from "./sidebar.module.css";


const Sidebar = ({ width=280, children }) => {
  const [isOpen, setOpen] = useState(false);
  const [xPosition, setX] = useState(width);
  const side = useRef();
  
  // button 클릭 시 토글
  const toggleMenu = () => {
    if (xPosition > 0) {
      setX(0);
      setOpen(true);
    } else {
      setX(width);
      setOpen(false);
    }
  };
  
  // 사이드바 외부 클릭시 닫히는 함수
  const handleClose = async e => {
    let sideArea = side.current;
    let sideCildren = side.current.contains(e.target);
    if (isOpen && (!sideArea || !sideCildren)) {
      await setX(width); 
      await setOpen(false);
    }
  }

  useEffect(()=> {
    window.addEventListener('click', handleClose);
    return () => {
      window.removeEventListener('click', handleClose);
    };
  })


  return (
    <div className={styles.container}>
      <div ref={side}  className={styles.sidebar} style={{ width: `${width}px`, height: '100%',  transform: `translatex(${-xPosition}px)`}}>
          <button onClick={() => toggleMenu()}
          className={styles.button} >
            {isOpen ? 
            <span>X</span> : <img src="images/avatar.png" alr="contact open button" className={styles.openBtn}/>
            }
          </button>
        
        <div className={styles.content}>{children}</div>
      </div>
    </div>
  );
};


export default Sidebar;

xPosition과 width 음수로 변경, toggleMenu 조건 변경된 코드입니다. 

 

 sidebar.module.css 

.container {
  background-color: #E3ECF1;
}
.sidebar {
  background-color: #E3ECF1;
  border-right: 4px solid #202020;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  transition: 0.4s ease;
  color: #202020;
  height: 100%;
  z-index: 99;
}
.button {
  position: relative;
  left: 330px; 
  top: 10px;
  width: 40px;
  height: 40px;
  z-index: 99;
  transition: 0.8s ease;
  border: 2px solid #202020;
  border-radius: 40px;
  overflow: hidden;
}
.openBtn {
  width: 100%;
  height: 100%;
}
.content {
  padding: 40px 40px 0 20px;
  position: relative;
  width: 100%;
}
.icon {
  margin: 0;
  color: #202020;
}

sidebar가 left에 붙게 수정하고, button 붙는 위치가 수정되었습니다.

 

 

 

 

헷깔리는 부분이나 오류가 있다면 언제든 댓글 남겨주세요! 

그럼 즐거운 코딩라이프되세요~~! 🙌

'mini-Projects > react' 카테고리의 다른 글

[react] 비밀번호 보기/숨기기 기능  (0) 2021.05.24
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함