본문 바로가기
Javascript

[JS] json.data로 아코디언 메뉴 구현

by 타로 스토리 2023. 5. 27.
반응형

웹사이트에서 자주 사용되는 아코디언 메뉴 입니다. 

리액트나 뷰등 프론트엔드 프레임워크를 사용해서 UI를 구성하다보니 순수 자바스크립트로 작성하는걸 자꾸 잊는거 같습니다. 그래서 기록으로 남겨두려 작성했습니다. 

외부 데이터를 사용하면서 UI를 생성하는 방식으로 작성 되었습니다. 

고정된 데이터일 경우엔 HTML로 직접 데이터를 작성해서 마크업 하면 되지만 관리자 페이지 등에서 작성된 데이터를 불러올 경우 외부 데이터를 사용해야 하기 때문에 JSON파일을 붙이는 방법으로 제작했습니다.

html

<!DOCTYPE html>
<html>
  <head>
    <title>Accordion Menu</title>
    <link rel="stylesheet" href="styles.css" />
    <link
  </head>
  <body>
    <div id="accordion">
      <!-- 자바스크립트 동적 마크업 -->
    </div>

    <script src="index.js"></script>
  </body>
</html>

UI를 JS에서 생성한후 적용하는 방식으로 제작했기 때문에 ID가 accordion인 div 요소만 만들어 주었습니다.

 

css

.header {
  background-color: #eaeaea;
  border: 1px solid #dadada;
  padding: 10px;
  cursor: pointer;
  margin: 0;
}

.header:hover,
.header.active {
  background-color: #555555;
  color: #dadada;
}

.panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
  padding: 0;
}

.panel.active {
  transition: max-height 0.35s ease-in;
}

.content {
  padding: 20px;
  line-height: 1.5;
}

선택한 아코디언 메뉴를 시각적으로 구분하기 위한 active클래스를 넣어주고 transition을 적용해 애니메이션을 적용합니다. 그 외 CSS는 아코디언 메뉴의 디자인만 적용합니다.

 

javascript

// JSON 파일에서 데이터를 가져오는 함수
async function getData() {
  try {
    const response = await fetch("data.json");
    if (!response.ok) {
      throw new Error("Network response was not ok");
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error(error);
  }
}

// 아코디언 UI 생성 함수
function createAccordion(Items) {
  const container = document.getElementById("accordion");
  Items.forEach((data, i) => {
    const header = document.createElement("h2");
    header.className = "header";
    header.textContent = data.heading;
    container.appendChild(header);

    const panel = document.createElement("div");
    panel.className = "panel";
    container.appendChild(panel);

    const contents = document.createElement("div");
    contents.className = "content";
    contents.textContent = data.content;
    panel.appendChild(contents);

    // 아코디언 헤더 클릭 이벤트 리스너 등록
    header.addEventListener("click", () => {
      togglepanel(i);
    });
  });
}

// 아코디언 콘텐츠 토글 함수
function togglepanel(index) {
  const headers = document.querySelectorAll(".header");
  const panels = document.querySelectorAll(".panel");
  const header = headers[index];
  const panel = panels[index];

  // CSS를 통한 비주얼 변경을 위한 클래스 토글
  headers.forEach((header, i) => {
    if (i !== index) {
      header.classList.remove("active");
    }
  });

  panels.forEach((panel, i) => {
    if (i !== index) {
      panel.classList.remove("active");
      panel.style.maxHeight = "0px";
    }
  });

  header.classList.toggle("active");
  panel.classList.toggle("active");

  // 높이값 Transition 설정
  panel.style.maxHeight =
    panel.clientHeight === 0
      ? panel.scrollHeight + "px"
      : (panel.style.maxHeight = "0px");
}

// UI 생성 함수 실행
async function accordion() {
  const Items = await getData();
  createAccordion(Items);
}

accordion();

데이터를 가져오는 함수, UI 생성 함수, Event Toggle 함수, 실행 함수로 구성합니다.

 

data.json

[
  {
    "heading": "Title1",
    "content": "첫번째 아코디언 내용"
  },
  {
    "heading": "Title2",
    "content": "두번째 아코디언 내용"
  },
  {
    "heading": "Title3",
    "content": "세번째 아코디언 내용"
  }
]

더미데이터로 사용할 JSON 파일입니다.

반응형

댓글