나는 마켓컬리에서
nav
와제품상세 페이지
를 맡았다. 우선 가장 금방 끝낼 수 있을 것 같은nav
를 먼저 만들었지만hover
에서hover
가 되는 것을 구현하는게 생각보다 오래걸렸다.
개발시간을 잡을때 내가 생각하는 시간의 x2를 해야한다는게 맞는 말인 것 같다. 😭
우선 카테고리를 hover
하게 되면 리스트 목록이 나오고 목록의 list에 hover
를 하게되면 한 번더 슬라이드가 되서 조금 더 자세한 목록들이 출력이 된다.
일단 목록에서 슬라이드된 메뉴를 보여주기 위해서는 슬라이드된 메뉴를 absoulte
로 고정하고 left:200px
값을 줬다.
그리고 hover리스트를 감싸고 있는 큰 부모박스의 스타일로 width: 220px, overflow:hidden
을 주고 전체 카테고리에 hover 됐을 때 width:450px
을 늘려주면 마치 슬라이드되서 나오는 것처럼 보이게 할 수 있다.
여기서 핵심
예를 들어 햄버거에 호버를하고 슬라이드된 메뉴에 마우스를 over할때 햄버거 목록이 계속 선택이 되어있는 것 처럼 구현해야한다.
<div className="menu-hover-box" style={allCategoriesHover ? { display: 'flex', width: `${hoverWidth}px` } : { display: 'none' }} onMouseLeave={this.allCategoriesHoverLeave}>
<div className="menu-hover">
<ul className="menu-hover-list">
{navbarList.map((list, index) => (
<NavBarHoverList displayShowIndex={displayShowIndex} list={list} index={index + 1} key={index} categoriesMenuHoverEnter={this.categoriesMenuHoverEnter} />
))}
</ul>
</div>
</div>
navbarList
를 map()
으로 각각의 list
를 <NavBarHoberList>
로 전달하는데 index값을 전달한다. index+1
하는 이유는 mock data
의 id값이 1부터 시작하기 때문
displayShowIndex
는 몇 번째의 목록 슬라이드 메뉴를 보여줄 것인지를 알기 위해 자식 인 <NavBarHoverList>
컴포넌트로 보낸다. 그리고 목록을 hover
하면 몇 번째 인덱스를 hover
했는지 전달하면 현재 어디를 hover
하고 있는지를 알 수 있다.
mosueOnLinkEnter = e => {
this.props.categoriesMenuHoverEnter(e.target.id);
};
render() {
const { displayShowIndex, index, list } = this.props;
return (
<li>
<Link to="#" id={index} className={'menu-hover-list-name ' + (parseInt(displayShowIndex) === list.navbarId ? 'hover-on' : null)} onMouseEnter={this.mosueOnLinkEnter}>
<span> {list.categoriesMenuName}</span>
</Link>
{parseInt(displayShowIndex) === index && (
<ul className="menu-sub-list">
{list.categoriesSubMenuName.map((list, index) => (
<li key={index}>
<Link to="#" className="sub-list-link">
<span className="sub-list-name">{list}</span>
</Link>
</li>
))}
</ul>
)}
</li>
);
}
// Nav Component
<ul className="menu-main-list">
<li className="menu1" onMouseEnter={this.allCategoriesHoverEnter}>
<Link to="#" className="menu1-link">
<FiMenu className="menu1-icon" />
<span className="menu-text">전체 카테고리</span>
</Link>
</li>
...
...
<div className="menu-hover-box" style={allCategoriesHover ? { display: 'flex', width: `${hoverWidth}px` } : { display: 'none' }} onMouseLeave={this.allCategoriesHoverLeave}>
<div className="menu-hover">
<ul className="menu-hover-list">
{navbarList.map((list, index) => (
<NavBarHoverList displayShowIndex={displayShowIndex} list={list} index={index + 1} key={index} categoriesMenuHoverEnter={this.categoriesMenuHoverEnter} />
))}
</ul>
</div>
</div>
// NavBarHoverList component
class NavBarHoverList extends React.Component {
mosueOnLinkEnter = e => {
this.props.categoriesMenuHoverEnter(e.target.id);
};
render() {
const { displayShowIndex, index, list } = this.props;
return (
<li>
<Link to="#" id={index} className={'menu-hover-list-name ' + (parseInt(displayShowIndex) === list.navbarId ? 'hover-on' : null)} onMouseEnter={this.mosueOnLinkEnter}>
<span> {list.categoriesMenuName}</span>
</Link>
{parseInt(displayShowIndex) === index && (
<ul className="menu-sub-list">
{list.categoriesSubMenuName.map((list, index) => (
<li key={index}>
<Link to="#" className="sub-list-link">
<span className="sub-list-name">{list}</span>
</Link>
</li>
))}
</ul>
)}
</li>
);
}
}
메뉴 카테고리에서 onMouseEnter
이벤트가 발생하면 allCategoriesHoverEnter
allCategoriesHoverEnter = () => {
this.setState({
allCategoriesHover: true,
hoverWidth: this.HOVER_WIDTH_TYPE1,
});
};
allCategoriesHover: true
값을 주게 되면 hover
카테고리가 display: flex
로 바뀌게 되고 목록 리스트가 출력이 된다.
hoverWidth: this.HOVER_WIDTH_TYPE1(220)
: hover에 관련된 최상위 부모 width
값을 220으로 수정