👉🏻스크롤 메뉴(Scroll Menu) 구현해보기
안녕하세요 TriplexLab 입니다.
이번에는 흔하게 많이들 작업하시는 스크롤 메뉴에관해서 살펴보도록 하겠습니다.
👉🏻참고링크
먼저 내 글중에서 마우스 이벤트 위치 관한글이 있는데 이것 보시고 이이서 글 보시면 이해하는데 도움이 될것 같습니다.
// scrollMenu.js
class ScrollMenu {
constructor(el) {
this.el = el;
this.$$ = (ele) => Array.from(document.querySelectorAll(ele));
this.$ = (ele) => document.querySelector(ele);
this._$ = (ele) => this.selector(ele);
this.store = { menuNames: [] };
this.init();
}
scroll() {
const { menuNames } = this.store;
//화면의 높이를 가져와서 3등분 한다.(2등분해도 된다.)
//항목이 3등분 지점안으로 올때 하이라이트를 줄려고 계산
let windowHeight = (window.innerHeight / 3).toFixed(0);
//본문에 다시 h태그를 가져온다.
menuNames.forEach((item) => {
//h태그 객체가 화면의 상단에서 얼마큼 떨어져 있는지 가져와서
let myPosition = item.getBoundingClientRect().top;
//그 거리가 -30에서 이전 화면의 높이 3등분 한 값보다 작으면
//함수실행 화면 상단에서 3분지1 지점 안으로 들어오면 작동하게끔
if (myPosition > -30 && myPosition < windowHeight) {
this.togglCss(item.id);
}
});
}
togglCss(targetId) {
const { targetMenu, addClassName } = this.el;
if (targetId === "") return;
//받아온 아이디값으로 메뉴에서 해당 아이디를 가진 객체에 highlights를 넣어준다.
this.$$("." + addClassName).forEach((item) => {
item.classList.remove(addClassName);
});
this.$(targetMenu)
.querySelector("#" + targetId)
.classList.add(addClassName);
}
init() {
const {
targetMenu,
targetView,
addIdName,
addClassName,
menuNames,
templateMenu,
} = this.el;
this.store.menuNames = Array.from(
this.$(targetView).querySelectorAll(menuNames)
);
const temp_html = this.store.menuNames
.map((item, idx) => {
item.setAttribute("id", `${addIdName}-${idx}`);
return templateMenu(item, idx);
})
.join("");
this.$(targetMenu).innerHTML = temp_html;
this.$(targetMenu).querySelector("li").classList.add(addClassName);
this.$(targetMenu)
.querySelectorAll("li")
.forEach((item) => {
item.addEventListener("click", (e) => {
const id = this.$(targetView).querySelector("#" + e.currentTarget.id);
const offsetEleY = id.getBoundingClientRect().top;
// 스크롤로 이동한 거리(window.pageYOffset) + 현재화면 기준으로한 상대경로 값(offsetEleY)을 합한 값으로 절대경로를 구할수 있습니다.
const scrollPosition = window.pageYOffset + offsetEleY - 30; // offsetTop에 30px 만큼 여백을 줌
window.scrollTo({ top: scrollPosition, left: 0, behavior: "smooth" });
});
});
window.addEventListener("scroll", () => this.scroll());
}
}
export default ScrollMenu;
scrollMenu.js 파일에서 객체를 정의한것을 아래에서 사용하는것입니다.
나중에 재사용하기 편하게 class로 만들었습니다. scrollMenu.js파일 import시키고 인스턴스만 호출하시면 됩니다.
자세한 내용은 아래에 주석을 참고하면 됩니다.!!
<script type="module">
import ScrollMenu from "./scrollMenu.js";
(function () {
new ScrollMenu({
targetMenu: ".menuDiv ul", //메뉴 항목을을 삽입시킬 곳
targetView: ".viewDiv", //컨텐츠 내용 (본문글)
addIdName: "toc-link", //메뉴 항목에 아이디를 추가할 이름
addClassName: "is-active", //메뉴 항목에 클래스를 추가할 이름
menuNames: ["h1,h2,h3,h4"], //특정 태그명 기준으로 스크롤이동 시킴
// templateMenu의 콜백함수
templateMenu: function (el, idx) {
const trimStr = el.innerText.split(" ").join(""); //띄어쓰기 제거
return `
<li id="toc-link-${idx}" class="item toc-link-${idx}">
<a href="javascript:void(0)">${trimStr}</a>
</li>
`;
},
});
})();
</script>
👉🏻파일공유
파일공유 합니다.
필요하신 분들은 다운로드 받으세요~ 😃✅👍🎉
👉🏻파일공유2
파일공유 합니다.
이것은 위에서 공유한 파일내용에서 기능을 더 추가한 것입니다.
new ScrollMenu({
type: 'tabs', //scroll | tabs 둘중에 하나 기능 설정할수 있습니다.
...
...
});
/*ScrollMenu 인스턴스에 type 옵션이 tabs인경우에 주석을 해지해서 사용하세요.*/
.viewDiv .section {display: none;}
.viewDiv .section.is-active {display: block;}
다운로드 받으셔서 사용해보세요~ 😃✅👍🎉
이것은 홍보, 마케팅의 이벤트 페이지 작업을 할때 유용하게 사용할것 같습니다.!!