.gif)
나는 마켓컬리에서
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으로 수정