write.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <div id="wrapper">
        <!-- action이 서버쪽 동적 페이지가 아니고 정적 html이 왔다? 이게-->
        <form method="get" action="write_action.html">
            <h1>JS와 LS로 만드는 게시판</h1>
            <!-- disabled 처리하면 서버로 넘어가지가 않음. hidden이 필요!-->
            제목 <input type="text" name="n_title" value="" required><br>
            지은이<input type="text" name="n_writer" value="" required><br>
            내용<br>
            <textarea name="n_cont" id="" cols="30" rows="10" required></textarea><br>
            관련언어(맥스 3개까지만)<br>
            JS<input type="checkbox" name="n_skill" value="js" onclick="f3ck(this)">
            Java<input type="checkbox" name="n_skill" value="java" onclick="f3ck(this)">
            Oracle<input type="checkbox" name="n_skill" value="oracle" onclick="f3ck(this)">
            HTML<input type="checkbox" name="n_skill" value="html" onclick="f3ck(this)">
            CSS<input type="checkbox" name="n_skill" value="css" onclick="f3ck(this)"><br>
            <!-- form 태그 안에 button속성은 자동으로 type이 submit 됨 -->
            <button type="submit">전송</button> &nbsp;&nbsp;&nbsp;<button type="submit">다시</button>
        </form>
    </div>
</body>
</html>
<script>
    // 체크 박스 맥스 3개까지만 체크 가능하도록 4개째 메시지와 함께, 4번째 껀 해제!
    const maxCnt = 3;
    let curCnt = 0;
    
    function f3ck(pThis) {
        if(pThis.checked){
            console.dir(pThis);
            curCnt++;   // 체크가 늘었으니 카운트 증가
        }
        if(!pThis.checked){
            curCnt--;  // 체크가 줄었으니 카운트 감소
        }
        if(maxCnt < curCnt){
            alert("체크박스는 3개까지만 체크 가능합니다.")
            pThis.checked = false; // 강제 체크 풀기
            curCnt--;       // 늘였던 카운트도 감소
        }
    }

</script>

jsp.js

// let title = location.href.split("?")[1].split("&")[0].split("=")[1]
    /* 
    인코딩함수     escape      encodeURI       encodeURIComponent
    디코딩함수     unescape    decodeURI       decodeURIComponent
     */
    // 위의 방식으로는 제대로 적용할 수 없음(case by case를 사람이 대처?)
    // 위의 상황을 일반화시킴(자동화)

    const request = {};     // 네임스페이스용 빈 객체 (안 빈 것이어도 상관없음)

    request.getParameter = function(pName){
        if(location.href.indexOf("?") == -1) return; // ?가 없으면 return
        
        let queryString = location.href.split("?")[1]; // ? 오른쪽 문자을 쿼리스트링이라 부름
        let items = queryString.split("&");
        for(let i=0; i<items.length; i++){
            let name = items[i].split("=")[0];
            let val = items[i].split("=")[1];
            if(name == pName){
                val = decodeURIComponent(val);
                val = val.replaceAll("+", " "); // 공백이 +로 넘어오기 때문에 재가공!
                return val;
            }

        }
        // return "name이 없습니다!"    // 개발중에는 이렇게 쓰자!
        return null;
    }
    
    // 같은 name이 여러개인 경우에 사용하는 메소드, 배열을 리턴
    request.getParameterValues = function(pName){
        if(!location.href.includes("?")) return; // ?가 없으면 return

        let arr = [];
        let queryString = location.href.split("?")[1];
        let items = queryString.split("&");
        for(let i=0; i<items.length; i++){
            let name = items[i].split("=")[0];
            let val = items[i].split("=")[1];
            if(name == pName){
                val = decodeURIComponent(val);
                val = val.replaceAll("+"," "); // 공백이 +로 넘어오기 때문에 재가공!
                arr.push(val) // return으로 멈추면 안되고, 끝까지 찾아야함 
            }
        }
        if(!arr.length) return null; // 아무것도 못 찾았다면 null 리턴
        return arr; //배열을 리턴
    }

writer_action.html

<!DOCTYPE html>
<meta charset="UTF-8">
<script src="./jsp.js"></script>
<script>
    let title = request.getParameter("n_title");
    let writer = request.getParameter("n_writer");
    let cont = request.getParameter("n_cont");
    let skills = request.getParameterValues("n_skill");

   // 1개 세트로 (관계형DB로 보자면 테이블의 1개 row로)
    let gul = {
        num: 0,     // primary key로 쓸 속성
        title:title,
        writer:writer,
        cont:cont,
        skills:skills,
        date: (new Date()).toLocaleDateString()
    }

    // localStorage에 저장
    const tblName = "uglyGesi";
    let dataArr = [];    // 그냥 선언, 빈 배열 (값이 없는 경우에 쓸 예정)

    if(localStorage.getItem(tblName)){
        dataArr = JSON.parse(localStorage.getItem(tblName));
        gul.num = dataArr[dataArr.length-1].num+1;
    }
    dataArr.push(gul); // 배열에 추가

    localStorage.setItem(tblName, JSON.stringify(dataArr));

    alert("글이 잘 입력되었습니다!");

    //|location.href = "list.html";     - 캐쉬를 쓸 수도 안쓸 수도 
    location.replace("list.html");      // 캐쉬 안쓴다.
</script>

Untitled

새로고침 할 때 마다 추가되는 것도 볼 수 있다.

Untitled

list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
<style>
    #modal{
        position: fixed;
        left: 0px; top:0px;
        width : 100vw; height: 100vh;
        background-color: rgba(148, 3, 148, 0.8);
        display:none;   /* 크기가 없는 상태로 안보임 */
    } 
    #mCont{
        width: 60%;
        height:70%;
        margin: 20px auto; /* 수평 가운대 정렬 */
        background-color: orange;
    }

</style>
</head>
<body>
<div id="modal">
    <div id="mCont">
        <form method="get" action="">
            <h1>상세보기</h1>
            <!--사용자에겐 보여줄 필요가 없는데, 프로그램상 필요한 값 hidden 사용-->
            <input type="hidden" name="n_num" value="">
            <!-- disabled 처리하면 서버로 넘어가지가 않음. hidden이 필요!-->
            제목 <input type="text" name="n_title" value=""><br>
            지은이<input type="text" name="n_writer" value="" disabled><br>
            내용<br>
            <textarea name="n_cont" id="" cols="30" rows="10"></textarea><br>
            관련언어(맥스 3개까지만)<br>
            JS<input type="checkbox" name="n_skill" value="js" onclick="f3ck(this)">
            Java<input type="checkbox" name="n_skill" value="java" onclick="f3ck(this)">
            Oracle<input type="checkbox" name="n_skill" value="oracle" onclick="f3ck(this)">
            HTML<input type="checkbox" name="n_skill" value="html" onclick="f3ck(this)">
            CSS<input type="checkbox" name="n_skill" value="css" onclick="f3ck(this)"><br>
            <!-- form 태그 안에 button속성은 자동으로 type이 submit 됨 -->
            <button type="submit" onclick="fsubmit('mod')">수정</button> &nbsp;&nbsp;&nbsp;
            <button type="submit" onclick="fsubmit('del')">삭제</button>
        </form>
    </div>
</div>
<div id="wrapper">
    <h1>어글리 게시판</h1>
    <div id="list"></div>
</div>
<script src="./jsp.js"></script>
<script>
// 그저 단순 게시판이 아니니, 한번 잘 고민해보고, 아이디어도 내보는 걸로
// 페이지 나누기 해봐요 (항상 외우지 말고, 생각하면서 흐름으로)
/*
    페이지당 몇개 글 출력
    전체 글 수
    페이지 수
    페이지별로 시작인덱스(글), 끝인덱스(글) 배열에 담아져 있기 때문
    */

const tblName = "uglyGesi"; // 로컬 스토리지 테이블 키값
let dataArr = JSON.parse(localStorage.getItem(tblName)); // 데이터 배열

/*
    1   0-9
    2   10-19
    3   20-29
*/

let page = request.getParameter("page"); 
if(!page) { // 만약 page 정보가 안 넘어 왔다면...
    page = 1; // 기본값 1과 무조건 첫 페이지로 지정
}

const cntPerPage = 10; // 페이지당 10개씩
let totalGulCnt = dataArr.length;
let pageCnt = Math.ceil(totalGulCnt / cntPerPage);  // 간단히 올림으로 해결
let startGulInx = (page - 1)* 10;
let endGulInx = startGulInx + cntPerPage;  // 반복문에 < 쓸거라 -1 필요없음
if(endGulInx > totalGulCnt){
    endGulInx = totalGulCnt;
}

const myForm = document.forms[0]; // id를 안주고 요렇게 써도 됨!
function fsubmit(pAct) {
    event.preventDefault(); // submit의 built-in 기능 (전송) 막기
    if(pAct == 'mod') {
        myForm.action = "modify_action.html";
    }

    if(pAct == 'del') {
        myForm.action = "del_action.html";
    }

    myForm.submit();
}
const myModal = document.querySelector("#modal");
const gList = document.querySelector("#list");

function fread(pNum) {
    event.preventDefault(); // built-in 기능 막기 (a태그의 href 기능 막기)
    // 빼먹는 사람들이 있어 변칙적으로 그냥 #을 붙이라고 함 (페이지내 이동)
    document.querySelector("[name=n_num]").value = pNum;

    myModal.style.display = "block";

    for(let i=0; i<dataArr.length; i++) {
        if(dataArr[i].num == pNum) { // 찾던 글
            document.querySelector("[name=n_title]").value = dataArr[i].title;
            document.querySelector("[name=n_writer]").value = dataArr[i].writer;
            document.querySelector("[name=n_cont]").value = dataArr[i].cont;
            
            // 체크박스를 어캐할 건지, dataArr[i].skills 있는 내용이 자동 체크되어야 함!
            // css 선택자를 잘 쓰면 프로그램이 심플하고 명확해짐
            let ckArr = dataArr[i].skills;
            for(let j=0; j<dataArr[i].skills.length; j++){
                document.querySelector(`[value=${ckArr[j]}]`).checked=true;
            }

            break; // 요런 걸 안 빼먹는 게 중요 여기서 return을 써도 됨
        }
    }
}

function fList() {
    let tblStr = `<table border=1>`;
        tblStr += `<tr><th>넘버</th><th>제목</th><th>지은이</th><th>날짜</th>`;
        for(let i=startGulInx; i<endGulInx; i++) {
            tblStr += `<tr>`;
            tblStr += `<td>${dataArr[i].num}</td>`;
            tblStr += `<td><a href="//naver.com" onclick="fread(${dataArr[i].num})">${dataArr[i].title}</a></td>`;
            tblStr += `<td>${dataArr[i].writer}</td>`;
            tblStr += `<td>${dataArr[i].date}</td>`;
            tblStr += `</tr>`;
        }
        tblStr += `</table>`;

        // 페이지 번호 출력하는 부분 추가
        let pageStr = ""
        for(let i=1; i <= pageCnt; i++) { 
            pageStr += `<a href="list.html?page=${i}">${i}</a>&nbsp&nbsp&nbsp;`
        }

        tblStr += pageStr; // 페이지 출력 리스트 추가

        tblStr += `<br><a href="write.html">글쓰기</a>`;
        gList.innerHTML = tblStr; // 화면에 뿌리기
}
window.addEventListener("DOMContentLoaded", function(){
    fList();
}); // 태그 해석만 끝나면 발생
// window.addEventListener("load", fList);          // 태그 해석 + 이미지 로딩완료에 발생
</script>
</body>
</html>

Untitled

페이징 버젼

Untitled