JAVASCRIPT -

스크롤 메뉴(Scroll Menu) 구현해보기 JavaScript ES6

  • -

👉🏻스크롤 메뉴(Scroll Menu) 구현해보기

안녕하세요 TriplexLab 입니다.

이번에는 흔하게 많이들 작업하시는 스크롤 메뉴에관해서 살펴보도록 하겠습니다.

👉🏻참고링크

먼저 내 글중에서 마우스 이벤트 위치 관한글이 있는데 이것 보시고 이이서 글 보시면 이해하는데 도움이 될것 같습니다.

 

MouseEvent 위치프로퍼티 정리

🖱 Event 위치프로퍼티 정리 안녕하세요 TriplexLab 입니다. 마우스 이벤트(MouseEvent) 객체에는 마우스 포인터의 위치와 관련된 다양한 프로퍼티들이 있는데요. 주로 아래와 같은 프로퍼티들이 자주

triplexblog.kr

// 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>

👉🏻파일공유

파일공유 합니다.
필요하신 분들은 다운로드 받으세요~ 😃✅👍🎉

scrollMenu.zip
0.00MB

👉🏻파일공유2

파일공유 합니다.
이것은 위에서 공유한 파일내용에서 기능을 더 추가한 것입니다.

new ScrollMenu({
  type: 'tabs', //scroll | tabs 둘중에 하나 기능 설정할수 있습니다.
  ...
  ...
});
/*ScrollMenu 인스턴스에 type 옵션이 tabs인경우에 주석을 해지해서 사용하세요.*/
.viewDiv .section {display: none;}
.viewDiv .section.is-active {display: block;}

다운로드 받으셔서 사용해보세요~ 😃✅👍🎉
이것은 홍보, 마케팅의 이벤트 페이지 작업을 할때 유용하게 사용할것 같습니다.!!

scrollMenu.zip
0.00MB

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.