티스토리 뷰
안녕하세요. 좋아요요정입니다!
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
- Prototype
- 파이썬
- Call
- 프로그래머스
- 선언
- 프론트엔드
- 프로토타입
- react
- 함수
- 타이핑효과
- JavaScript
- JS
- 타이핑
- 코딩테스트
- 상속
- 스택
- 자바스크립트
- 프로퍼티
- 팀러버덕
- SET
- 생성자함수
- 면접대비
- Python
- 리액트
- 메서드
- 복제
- this
- 면접
- 스터디
- 객체
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |