6. JavaScript board-list 기능 만들기

 

목차

    1. 디자인 시안 확인

    board-list.html
    게시글이 없는 경우 (비로그인시), 게시글이 는 경우(로그인시)

    2. (사전 기반 지식) 자바스크립트의 if문 조건식의 평가 방식

    if (조건) {
        // 조건이 true일 때 실행되는 코드
    }
    자바스크립트에서 if 문 안에 들어가는 조건식은 Boolean 값으로 평가됩니다.
    즉, 조건식이 true로 평가되면 코드 블록이 실행되고, false로 평가되면 실행되지 않습니다.
    • 자바 스크립트 "truthy"와 "falsy”

    다음은 자바스크립트에서 거짓(false)으로 평가되는 "falsy" 값

    false: Boolean 값 false
    0: 숫자 0
    "": 빈 문자열 (길이가 0인 문자열)
    null: 값이 없음을 나타내는 값
    undefined: 정의되지 않은 상태를 나타내는 값
    NaN: 숫자가 아님을 나타내는 값 (Not-a-Number)
    
    if (0) {
        // 이 코드는 실행되지 않습니다. (0은 falsy 값이므로)
    }

     

    위에 나열된 "falsy" 값들을 제외한 모든 값은 "truthy" 값으로 간주된다. 즉, if 문에서 참(true)으로 평가된다.

    true
    1, -1, 또는 다른 모든 숫자
    "hello"와 같은 길이가 1 이상인 문자열
    객체 ({}, [] 등)
    
    if ("둘리") {
        // 이 코드는 실행됩니다. ("둘리"는 truthy 값이므로)
    }
    
    if (1) {
        // 이 코드는 실행됩니다. ("둘리"는 truthy 값이므로)
    }
    
    if (-1) {
        // 이 코드는 실행됩니다. ("둘리"는 truthy 값이므로)
    }

    3. 코드

    board-list.html
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>게시글 목록</title>
        <link rel="stylesheet" href="../css/common.css" />
        <link rel="stylesheet" href="../css/header.css" />
        <link rel="stylesheet" href="../css/border.css" />
      </head>
      <body>
        <header>
          <nav class="nav-container">
            <div class="nav-item">
              <span class="menu-link" id="board">게시판</span>
            </div>
            <div class="nav-item" id="authLinks">
              <span class="menu-link" id="signIn">로그인</span>
              <span class="menu-link" id="signUp">회원가입</span>
            </div>
          </nav>
        </header>
        <main class="content-wrapper">
          <section class="title-box">
            <h1>게시글 상세보기 by JS</h1>
          </section>
          <div class="content-box">
            <div class="board-box">
              <div class="head">
                <div class="head-1">번호</div>
                <div class="head-2">제목</div>
                <div class="head-3">작성자</div>
                <div class="head-4">작성일</div>
                <div class="head-5">조회수</div>
              </div>
              <div class="board-content-box">
              </div>
              <!-- 페이징 영역 -->
              <div class="botton-box">
                <div class="page-box">
                  <span class="left">◀</span>
                  <div class="num-box">
                    <span class="num">1</span>
                  </div>
                  <span class="right">▶</span>
                </div>
                <div class="write-button-box">
                  <button type="button" class="btn">글쓰기</button>
                </div>
              </div>
            </div>
          </div>
        </main>
    
        <script src="../js/header.js"></script>
        <script src="../js/boardList.js"></script>
      </body>
    </html>
    boardList.css
    .content-box {
      display: flex;
      flex-direction: column;
      width: 100%;
      max-width: 1000px;
    }
    .board-box {
      display: flex;
      flex-direction: column;
    }
    
    .head,
    .board {
      border-bottom: 1px solid black;
      display: flex;
      justify-content: space-between;
      padding: 10px;
      align-items: center;
    }
    
    /* 제목, content 공간 영역 맞추기 */
    .head-1,
    .board-1 {
       /* flex 속성 (고정 너비) */
       flex: 0 0 80px;
    }
    
    .head-2,
    .board-2 {
       /* 가변 너비 */
       flex: 1;
       text-align: left;
       padding-left: 10px;
       padding-right: 10px;
    }
    
    .head-3,
    .board-3,
    .head-4,
    .board-4,
    .head-5,
    .board-5 {
       /* 고정 너비 */
       flex: 0 0 100px;
    }
    
    /* 하단 영역 */
    .button-box {
      display: flex;
      flex-direction: column;
      margin-top: 20px;
    }
    
    .page-box {
      display: flex;
      justify-content: center;
      padding: 20px;
    }
    
    .write-button-box {
      display: flex;
      justify-content: flex-end;
    }
    boardList.js
    // 샘플 데이터 입력
    const sampleBoardList = [
      {
        id: 1,
        title: "첫번째 게시글",
        content: "첫번째 게시글의 내용 입니다.",
        username: "홍길동",
        today: "2024.08.25",
        count: 5,
      },
      {
        id: 2,
        title: "두번째 게시글",
        content: "두번째 게시글의 내용 입니다.",
        username: "이몽룡",
        today: "2024.08.25",
        count: 5,
      },
      {
        id: 3,
        title: "세번째 게시글",
        content: "세번째 게시글의 내용 입니다.",
        username: "성춘향",
        today: "2024.08.25",
        count: 14,
      },
      {
        id: 4,
        title: "네번째 게시글",
        content: "네번째 게시글의 내용 입니다.",
        username: "변학도",
        today: "2024.08.25",
        count: 21,
      },
      {
        id: 5,
        title: "다섯번째 게시글",
        content: "다섯번째 게시글의 내용 입니다.",
        username: "심청",
        today: "2024.08.25",
        count: 51,
      },
    ];
    
    localStorage.setItem("boardList", JSON.stringify(sampleBoardList));
    document.addEventListener("DOMContentLoaded", () => {
      // DOM 접근
      const boardContainer = document.querySelector(".board-content-box"); // 컨텐트를 넣을 Element 선택
      const writeButton = document.querySelector(".btn"); // 글쓰기 버튼 Element 선택
      const paginationContainer = document.querySelector(".num-box");
    
      // 로컬 스토리지에서 게시글 목록 가져오기
      const storedBoardList = JSON.parse(localStorage.getItem("boardList"));
    
      if (storedBoardList) {
        storedBoardList.reverse();
      }
      // 페이징 처리 필요한 변수
      let currentPage = 0;
      const limit = 2; // 한 페이지당 게시글 수
      loadPosts(currentPage);
    
      // 게시글 목록을 내림차순으로 정렬하기
      // 게시글을 로드 하는 함수
      function loadPosts(page) {
        const offset = page * limit;
        const end =
          offset + limit > storedBoardList.length
            ? storedBoardList.length
            : offset + limit;
    
        let postElements = ""; // 게시글 HTML 요소를 저장할 변수
    
        // 방어적 코드 작성
        if (storedBoardList != null && storedBoardList.length > 0) {
          // 반복문을 사용()
          for (let i = offset; i < end; i++) {
            postElements += `<div class="board" data-id=${storedBoardList[i].id}>
             <div class="board-1">${i + 1}</div>
             <div class="board-2">${storedBoardList[i].title}</div>
             <div class="board-3">${storedBoardList[i].username}</div>
             <div class="board-4">${storedBoardList[i].today}</div>
             <div class="board-5">${storedBoardList[i].count}</div>
             </div>`;
          }
          boardContainer.innerHTML = postElements;
    
          // 페이지 네이션 생성
          createPagination(storedBoardList, page);
        } else {
          // 게시글이 없는 경우 메세지 표시
          boardContainer.innerHTML =
            '<div class="no-list" style="text-align: center; margin-top: 20px">조회된 게시글이 없습니다.</div>';
        }
      }
      // 페이지 네이션 생성 함수 선언
      function createPagination(boardList, currentPage) {
        // 전체 게시글 수, 한 페이지당 보여질 게시글 수
        const totalPosts = boardList.length; // 전체 게시글 수
        const totalPages = Math.ceil(totalPosts / limit); // 전체 페이지 수
        // 페이지 번호 HTML 저장할 변수
        let paginationHTML = "";
        for (let i = 0; i < totalPages; i++) {
          paginationHTML += `<span class="num" data-page="${i}">${i + 1}</span>`;
        }
        paginationContainer.innerHTML =  paginationHTML;
    
        // 생성된 페이지 번호의 요소 접근 (동적 할당)
        const pageNumbers = document.querySelectorAll('.num');
        // 현재 페이지 번호에 스타일 적용
        pageNumbers[currentPage].style.backgroundColor = 'grey';
        pageNumbers[currentPage].style.fontWeight = 600;
    
        pageNumbers.forEach((pageNumber) => {
          pageNumber.addEventListener('click', (event) => {
            // console.log('event',event);
            // console.log('event.target',event.target);
            // console.log('event.target.dataset',event.target.dataset);
            // console.log('event.target.dataset.page',event.target.dataset.page);
            // 해당하는 번호를 가지고 와서 다시 렌더링
            const targetPageNumber = parseInt(event.target.dataset.page);
            loadPosts(targetPageNumber);
          });
        });
    
        // 글쓰기 버튼 눌렀을 경우 -> 글쓰기 페이지 이동 처리
        writeButton.onclick = function(){
          location.href = "board-write.html";
        }
    
        // 해당 row 게시글을 눌렀을 경우 -> 상세보기 화면 이동 처리
      }
    });

    4. data-* 속성 및 dataset 개념

    1. data-* 속성

    data-* 속성은 HTML5에서 제공하는 사용자 정의 데이터 속성이다. 이 속성을 사용하면 HTML 요소에 데이터를 저장할 수 있으며, 이 데이터는 JavaScript로 쉽게 접근할 수 있다.

    • data-* 속성의 이름은 반드시 data-로 시작하고, 그 뒤에 사용자 정의 키를 붙일 수 있다. 예를 들어, data-id, data-user, data-index 등이 가능하다.
    <div data-id="123" data-name="둘리1"></div>

    2. dataset 객체

    dataset 객체는 JavaScript에서 HTML 요소의 data-* 속성에 접근할 수 있도록 해주는 특수한 객체이다. dataset 객체를 사용하면 data-*로 시작하는 모든 속성에 접근할 수 있으며, 이를 통해 데이터 값을 가져오거나 변경할 수 있다.

    const myDiv = document.getElementById('myDiv');
    
    // data-id 속성에 접근
    console.log(myDiv.dataset.id); // 출력: 123
    
    // data-name 속성에 접근
    console.log(myDiv.dataset.name); // 출력: 둘리
    
    // data-name 속성의 값을 변경
    myDiv.dataset.name = "고길동";
    console.log(myDiv.dataset.name); // 출력: 고길동

    JS 목차로 돌아가기