본문으로 바로가기

7. JavaScript boardWrite.js 글 쓰기 기능 만들기

category JavaScript 2024. 12. 28. 15:35

 

디자인 시안 확인 board-write.html

 

: 비 로그인 시 로그인 페이지로 리다이렉션 처리 됨


: 파일 미리 보기 기능 구현

board-write.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/boardWrite.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="form-title">
            <h1>글쓰기 by JS</h1>
        </section>

        <section>
            <table>
                <tr>
                    <th>제목</th>
                    <td>
                        <input type="text" class="inputs title">
                    </td>
                </tr>
                <tr>
                    <th>작성자</th>
                    <td>
                        <input type="text" class="inputs username" readonly>
                    </td>
                </tr>
                <tr>
                    <th>첨부파일</th>
                    <td>
                        <input type="file" class="file" accept="image/*">
                    </td>
                </tr>
                <tr>
                    <th>내용</th>
                    <td>
                        <div class="img-box" >이미지 미리보기</div>
                        <textarea name="" id="" class="content"></textarea>
                    </td>
                </tr>
            </table>

            <div class="btn-area">
                <button type="button" class="btn">글쓰기</button>
            </div>

        </section>
      
    </main>
      
      <script src="../js/header.js"></script>
      <script src="../js/boardWrite.js"></script>
</body>
</html>

boardWrite.css

.content {
    width: 95%;
    height: 300px;
    font-size: 18px;
    border: none;
    resize: none;
    margin-top: 5px;
}

.img-box {
    width: 100%;
    display: flex;
    justify-content: center;
}

.img-box img {
    width: 100%; 
    max-width: 300px;
}

header.js 코드 추가

// ... 생략 
// 코드 추가 
// 로그인 상태가 아니면 지정된 페이지로 리다이렉션 
function redirectToPageIfNotLoggedIn(page) {
    // 로컬 스토리지 접근 - user key 값 여부 확인 
    const loggedInUser = localStorage.getItem('user');
    if(loggedInUser === null) {
        location.href = `${page}.html`;
    }
}

임시 코드 - boardWrite.js

 

// 로그인 상태 여부 
redirectToPageIfNotLoggedIn('sign-in');

document.addEventListener('DOMContentLoaded', function() {
    
    // 사용 할 요소에 접근 
    const title = document.querySelector('.title');
    const username = document.querySelector('.username');
    const fileInput = document.querySelector('.file');
    const imgViewBox = document.querySelector('.img-box');
    const content = document.querySelector('.content');
    const button = document.querySelector('button');
    const day = new Date(); 

    // 사용자 선택한 이미지를 저장할 공간이 필요 
    let imageData = null; 
    // 사용자 정보 가져 오기 
    const getUser = JSON.parse(localStorage.getItem('user'));
    username.value = getUser.username;

    // 파일 미리보기 기능 만들기
    function fileUpload(event) {
        
        const file = event.target.files[0];
        //console.log('file', file);
        // 파일 크기 유효성 검사 
        // 1024 * 1024  * 5 =  (5MB) 이하만 허용 
        if(file.size >= 5242880) { 
            alert('첨부 파일은 5MB 이하만 가능 합니다');
            event.target.value = "";
            return; 
        }
        // 파일 타입 유효성 검사 
        const validFileTypes = ['image/jpeg', 'image/png', 'image/gif'];
        if(!validFileTypes.includes(file.type))   {
            alert('유효한 파일 타입이 아닙니다.(jpeg, png, gif만 허용');
            return; 
        } 

        // 파일 미리보기 기능 
        const reader = new FileReader();
        reader.readAsDataURL(file); // Base64 인코딩 바이트 단위 데이터를 -- 64개 문자로 표현하는 인코딩 방식
        reader.onload = function (e) {
            console.log('Base64', e.target.result);
            imgViewBox.innerHTML = `<img src="${e.target.result}" alt="Upload Image">`;
            // 글 저장시에 로컬스토리지에 바이너리 데이터를 -- 64 인코딩 저장 
            imageData = reader.result;
        }
    }

    // 글 저장하는 기능 만들기 
    function saveBoard() {
        // 유효성 검사 
        if(title.value === "") {
            alert('제목을 입력하시오');
            return;
        }
        
        if(content.value === "") {
            alert('내용을 입력하시오');
            return;
        }

        // 로컬 스토리지에 게시글 전체 목록 가져오기 
        let boardList = JSON.parse(localStorage.getItem('boardList') || [] );

        // 고유 ID 생성 
        const newId = generateUniqueId(boardList);

        // 객체 리터럴 표기법 사용 
        const board = {
            id: newId, 
            title : title.value,
            content : content.value, 
            username: username.value, 
            today:  `${day.getFullYear()}.${day.getMonth() + 1}.${day.getDate()}`,
            count: 0, 
            imgData: imageData
        };
        
        // 배열에다가 생성한 객체 추가 
        boardList.push(board);

        // 로컬 스토리지에 저장 (배열 전체)
        localStorage.setItem("boardList", JSON.stringify(boardList));
        // 페이지 이동 처리 
        location.href = 'board-list.html';
    }

    // 고유 아이디 생성 함수 
    function generateUniqueId(boardList) {
        return boardList.length > 0  ? boardList[boardList.length - 1].id + 1 :  1 ;
    }
    
    // 이벤트 리스너 등록 처리 - file change 
    fileInput.addEventListener('change', fileUpload);
    button.addEventListener('click', saveBoard);
});