-
JS / 바닐라로 앵커트메뉴, 메뉴엑티브, 스티키 만들기Web dev/JavaScript 2023. 4. 23. 14:17728x90반응형
이전에 스티키 기능만 넣은 메뉴를 만들었다.
더불어 메뉴를 누르면 앵커드기능과 스크롤위치에 따른 메뉴 엑티브기능을 만들었다.
앵커드 기능
1) 각 컨텐츠의 위치 구하기 offsetTop; 사용, 제이쿼리는 offset().top 사용
2) scrollTo({ top:ContentsBoxPosition, behavior:'smooth'}) 메서드 사용, 스무스옵션을 안쓰면 뚝뚝 끊김.
3) 버튼들에게 이벤트리스너 주기
anchor(){ let tabBtn = document.querySelectorAll(".category_list li"); let contentsBox = document.querySelectorAll(".contents_box"); function addEvent(idx){ // let ContentsBoxPosition = contentsBox[idx].getBoundingClientRect().top; // 위처럼 하면 랜딩되었을때 값이 구해져서 사용하기 부적합 따라서 아래처럼 구함 let ContentsBoxPosition = contentsBox[idx].offsetTop; tabBtn[idx].addEventListener("click",function(){ // 제이쿼리를 사용하면 animate() 메서드를 사용할 수 있다. window.scrollTo({ top:ContentsBoxPosition, behavior:'smooth'}); js.flag = true; }) } for(i=0; i < tabBtn.length; i++){ addEvent(i) } }
메뉴 스티키 효과는 이전 글에서 구현해놨었다.
스크롤 위치에 따른 메뉴 엑티브 효과
1) 각 컨텐츠 위치구해서 배열에 담기
2) flag 객체생성, 앵커드기능에서 앵커드이동중일때 동작안하게 하도록 예외처리, 이거 때문에 한참 버벅임..
const js = { flag:false, scrollEvt(){ let categoryInner = document.querySelector(".category_tab_inner"); let scrollPosition = document.documentElement.scrollTop; let tabBtn = document.querySelectorAll(".category_list li"); let contentsBox = document.querySelectorAll(".contents_box"); let categoryMenuPosition = document.querySelector(".category_tab_wrap").getBoundingClientRect().top; let curContentsArr = []; // 메뉴 스티키 기능 if(0 >= categoryMenuPosition){ categoryInner.classList.add("fixed"); }else{ categoryInner.classList.remove("fixed"); } // 메뉴 엑티브 효과 function addActive(i){ // 각 컨텐츠 위치구하기 let curCentents = contentsBox[i].offsetTop; curContentsArr.push(curCentents); // 버튼 앵커를 누르면 이동할떄 마다 엑티브 효과가 생겨서 끝날때 한번만 실행하도록했다. // anchor 메뉴 버튼을 누르면 true, 앵커드 후 도착하면 false if(scrollPosition === curContentsArr[i]){ js.flag = false; } // js.flag가 false 일떄 동작 // curContentsArr 각 위치값을 배열에 저장, 체이닝으로 더 줄여써도 되지만 일부러 배열을 한번 더 만듦 // 어떤사람은 각 컨텐츠위치값 + 각 컨테츠 높이값을 더해서 조건문을 쓰지만 나중에 아코디언메뉴가 있는 페이지지일때 하면될듯싶어 그냥했다. if(scrollPosition >= curContentsArr[i] && !js.flag){ tabBtn.forEach(function(idx){idx.classList.remove("on");}); tabBtn[i].classList.add("on"); } }; for(i=0; i < tabBtn.length; i++){ addActive(i) } }, anchor(){ let tabBtn = document.querySelectorAll(".category_list li"); let contentsBox = document.querySelectorAll(".contents_box"); function addEvent(idx){ // let ContentsBoxPosition = contentsBox[idx].getBoundingClientRect().top; let ContentsBoxPosition = contentsBox[idx].offsetTop; // let ContentsBoxHeight = contentsBox[idx].offsetHeight; tabBtn[idx].addEventListener("click",function(){ window.scrollTo({ top:ContentsBoxPosition, behavior:'smooth'}); js.flag = true; }) } for(i=0; i < tabBtn.length; i++){ addEvent(i) } }, init(){ window.addEventListener("scroll",js.scrollEvt); js.anchor(); } } js.init();
코드전체
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>카테고리 탭</title> <link rel="stylesheet" type="" href="./css/reset.css"> <style> .fixed{position: fixed; top: 0; left: 0; right: 0;} .visual{height: 500px; background-color: skyblue; margin-bottom: 50px;} .contents_box{height: 500px;} .footer{height: 500px; background-color: #000;} .category_tab_wrap{height: 38px; margin: 50px;} .category_tab_inner{max-width: 1200px; margin: 0 auto;} .category_list{display: flex; justify-content: center;} .category_list .item + .item{margin-left: 10px;} .category_list .item a{display: block; padding: 10px 15px; border-radius: 50px; border: 1px solid #000; background-color: #fff;} .category_list .item.on a{background-color: #000; color: #fff;} </style> </head> <body> <div class="visual">비쥬얼</div> <div class="category_tab_wrap"> <div class="category_tab_inner"> <ul class="category_list"> <li class="item on"><a href="javascript:;" title="한식 선택">한식</a></li> <li class="item"><a href="javascript:;" title="양식 선택">양식</a></li> <li class="item"><a href="javascript:;" title="중식 선택">중식</a></li> <li class="item"><a href="javascript:;" title="일식 선택">일식</a></li> <li class="item"><a href="javascript:;" title="기타 선택">기타</a></li> </ul> </div> </div> <div class="contents_box" style="background-color: orange;">한식</div> <div class="contents_box" style="background-color: yellow;">양식</div> <div class="contents_box" style="background-color: red;">중식</div> <div class="contents_box" style="background-color: blue;">일식</div> <div class="contents_box" style="background-color: skyblue;">기타</div> <div class="footer">풋터</div> </body> <script> const js = { flag:false, scrollEvt(){ let categoryInner = document.querySelector(".category_tab_inner"); let scrollPosition = document.documentElement.scrollTop; let tabBtn = document.querySelectorAll(".category_list li"); let contentsBox = document.querySelectorAll(".contents_box"); // window.pageYOffset let categoryMenuPosition = document.querySelector(".category_tab_wrap").getBoundingClientRect().top; let curContentsArr = []; if(0 >= categoryMenuPosition){ categoryInner.classList.add("fixed"); }else{ categoryInner.classList.remove("fixed"); } function addActive(i){ let curCentents = contentsBox[i].offsetTop; curContentsArr.push(curCentents); if(scrollPosition === curContentsArr[i]){ js.flag = false; } if(scrollPosition >= curContentsArr[i] && !js.flag){ tabBtn.forEach(function(idx){idx.classList.remove("on");}); tabBtn[i].classList.add("on"); } }; for(i=0; i < tabBtn.length; i++){ addActive(i) } }, anchor(){ let tabBtn = document.querySelectorAll(".category_list li"); let contentsBox = document.querySelectorAll(".contents_box"); function addEvent(idx){ // let ContentsBoxPosition = contentsBox[idx].getBoundingClientRect().top; let ContentsBoxPosition = contentsBox[idx].offsetTop; let ContentsBoxHeight = contentsBox[idx].offsetHeight; tabBtn[idx].addEventListener("click",function(){ window.scrollTo({ top:ContentsBoxPosition, behavior:'smooth'}); js.flag = true; }) } for(i=0; i < tabBtn.length; i++){ addEvent(i) } }, init(){ window.addEventListener("scroll",js.scrollEvt); js.anchor(); } } js.init(); </script> </html>
728x90반응형'Web dev > JavaScript' 카테고리의 다른 글
JS / sort() 매서드로 정렬하기 (0) 2023.04.30 JS / 객제 지향 프로그래밍 추상화,캡슐화,상속,다형성 (0) 2023.04.30 JS / 바닐라로 sticky 스티키 메뉴 구현하기 (0) 2023.04.16 JS / 바닐라로 video play(), pause() 구현하기 (0) 2023.02.26 JS / 정규식으로 콤마찍기 (0) 2023.02.26