본문 바로가기

DOM

DOM 기초(9) - 댓글 구현 기능 보강(CRUD), 게시판 기초

728x90
반응형

1) 코드 실습

    1-1) 댓글(CRUD) - 총 댓글 개수 표시 및 Update 기능 보강
    1-2) 게시판 기초

 

 

 

 

 

1) 코드 실습

1-1) 댓글(CRUD) - 총 댓글 개수 표시 및 Update 기능 보강

댓글 구현
- submitHandler

   >> state(데이터 타입: 배열): []
         위의 "state" 배열에 데이터를 쌓는 것이 전부이다!!


- instance 변수(데이터 타입: Object):
   >> new Comment(value)
   >> value : TEXT 입력폼에 입력한 값

 

const state= [];

const instance = {
	userid: 'web7722',
	Content: content,
	updated: false,
	updateValue: '',
	now: '....',
}

addComment(instance);

state.push(instance);


// 처음 state는 빈 배열([])이지만 여기에 push 메서드를 써서 아래와 같이 class(Comment class)로 생성한 객체(instance)를 순차적으로 추가함!!
state = [
	{
		userid: 'web7722',
		content: 'input' 박스 내용,
		updated: false,
		updateValue: '',
		now: '....',
	},
	{
		userid: 'web7722',
		content: 'input' 박스 내용,
		updated: false,
		updateValue: '',
		now: '....',
	},
	{
		userid: 'web7722',
		content: 'input' 박스 내용,
		updated: false,
		updateValue: '',
		now: '....',
	}, ...
]

 


create의 범위 : addComment() 까지 해당함!!

Read의 범위 : drawing() 부터 시작함!!

 

drawing()의 역할
drawing 함수: state 배열 안에 있는 객체를 element로 바꿔주는 함수

 

내가 화면에 무엇인가를 바꾸고자 할 때 순서

  1. state 변수에 있는 내용을 수정함!
  2. state 변수에 있는 내용으로 화면을 만듦!

즉, 데이터가 바뀌면 화면이 바뀐다!!

 

 

 

comment.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./public/css/comment.css" />
  </head>
  <body>
    <div>
      <ul class="comment">
        <li class="comment-form">
          <form id="commentFrm">
            <h4>
              댓글쓰기
              <span></span>
            </h4>
            <span class="ps_box">
              <input
                type="text"
                placeholder="댓글 내용을 입력해주세요."
                class="int"
                name="content"
              />
            </span>
            <input type="submit" class="btn" value="등록" />
          </form>
        </li>
        <li id="comment-list"></li>
      </ul>
    </div>
    <script src="./public/js/comment.js" type="text/javascript"></script>
  </body>
</html>

 

 

comment.css

* {
  margin: 0;
  padding: 0;
}

ul,
li {
  list-style: none;
}

.comment {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  padding: 30px;
  width: 600px;
  margin: 0 auto;
}

.comment > li {
  margin-top: 20px;
}

.comment > li:nth-child(1) {
  margin: 0px;
}

.comment-row {
  display: flex;
  justify-content: space-between;
  flex-direction: row;
}

.comment-row {
  margin-top: 20px;
  width: 100%;
}

.comment-row > li:nth-child(2) {
  flex-shrink: 0;
  flex-grow: 1;
  padding-left: 25px;
  z-index: 1;
  width: 100%;
}

.comment-row > li:nth-child(2) {
  width: 85px;
}

.comment-form > form {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
}

.comment-form > form > h4 {
  width: 100%;
  margin: 14px 0 14px 0;
}

.comment-content {
  cursor: pointer;
  word-break: break-all;
  padding-right: 25px;
}

.ps_box {
  display: block;
  position: relative;
  width: 80%;
  height: 51px;
  border: solid 1px #dadada;
  padding: 10px 14px 10px 14px;
  background: #fff;
  box-sizing: border-box;
}

.ps_box > input {
  outline: none;
}

.int {
  display: block;
  position: relative;
  width: 100%;
  height: 29px;
  padding-right: 25px;
  line-height: 29px;
  border: none;
  background: #fff;
  font-size: 15px;
  box-sizing: border-box;
  z-index: 10;
}

.btn {
  width: 18%;
  padding: 18px 0 16px;
  text-align: center;
  box-sizing: border-box;
  text-decoration: none;
  border: none;
  background: #333;
  color: #fff;
  font-size: 14px;
}

.comment-delete-btn {
  display: inline-block;
  margin-left: 7px;
  cursor: pointer;
}

.comment-update-input {
  border: none;
  border-bottom: 1px solid #333;
  font-size: 16px;
  color: #666;
  outline: none;
}

 

 

comment.js

const commentFrm = document.querySelector("#commentFrm");
const commentList = document.querySelector("#comment-list");
const totalContent = document.querySelector("h4 > span");
const state = [];

class Comment {
  constructor(content) {
    this.userid = "web7722";
    this.Content = content;
    // this.date = "2022-11-16";
    this.now = new Date();
    this.updated = false;
    this.updateValue = "";
  }

  // 대문자와 소문자로 content를 구분한 이유는 이름을 동일하게 설정 시 무한루프를 돌게 되기 때문!!
  set Content(value) {
    if (value.length === 0) {
      // alert("content의 내용을 채워주세요!");
      throw new Error("content의 내용을 채워주세요!");
    }
    this.content = value;
  }

  getToday(separator = "") {
    const date = this.now;
    let mm = date.getMonth() + 1; // "getMonth()"는 0 ~ 11로 각 월을 표시하기에 1 ~ 12월을 표현하기 위해 1을 더해준다!!
    let dd = date.getDate();
    let yyyy = date.getFullYear();
    mm = (mm > 9 ? "" : "0") + mm; // ex) 6 >> "06", 12 >> 12
    dd = (dd > 9 ? "" : "0") + dd;
    const arr = [yyyy, mm, dd];
    return arr.join(separator);
  }
}

function totalRecord() {
  totalContent.innerHTML = `(${state.length})`; // 템플릿 리터럴
  // total.innerHTML = "(" + list.length + ")"; // 바로 위의 코드를 "+" 연산자를 써서 문자열을 더해준 방식(실행 결과는 동일함!!)
}

function addComment(instance) {
  state.push(instance);
}

function createRow(index) {
  const ul = document.createElement("ul");
  const li1 = document.createElement("li");
  const li2 = document.createElement("li");
  const li3 = document.createElement("li");

  const deleteBtn = document.createElement("span");

  ul.append(li1);
  ul.append(li2);
  ul.append(li3);

  ul.setAttribute("class", "comment-row");
  ul.setAttribute("data-index", index);
  // ul.dataset.index = index; // 바로 위의 "ul.setAttribute("data-index", index);" 코드와 동일함!!
  li1.setAttribute("class", "comment-id");
  li2.setAttribute("class", "comment-content");
  // li2.addEventListener("click", function () {
  //   console.log(index, "hello world!");
  // });
  li3.setAttribute("class", "comment-date");
  deleteBtn.setAttribute("class", "comment-delete-btn");
  deleteBtn.innerHTML = "❌"; // Tip: mac 사용자의 경우, fn 키를 누르면 해당 코드 라인에 있는 "X"와 같은 이모지를 골라서 사용 가능함!!

  /*
  // 여기까지 return 값
  <ul class='comment-row' data-index="1">
    <li class='comment-id'></li>
    <li class='comment-content'></li>
    <li class='comment-date'></li>
  </ul>
  */

  li1.innerHTML = state[index].userid;
  // li2.innerHTML = state[index].content;
  if (state[index].updated) {
    const input = document.createElement("input");
    input.addEventListener("keyup", function (e) {
      // e.keycode는 각 키보드의 키마다 해당하는 키 코드(번호)를 확인할 수 있는데 enter 키는 키 코드가 13이다!!
      if (e.keyCode === 13) {
        state[index].content = e.target.value;
        state[index].updated = false;
        drawing();
      } else {
        state[index].updateValue = e.target.value;
      }
    });
    input.setAttribute("class", "comment-update-input");
    // <input type="text" class="comment-update-input" />
    input.value = state[index].updateValue;
    li2.append(input);
  } else {
    li2.innerHTML = state[index].content;
    li2.append(deleteBtn);
  }
  li3.innerHTML = state[index].getToday("/");

  /*
  // 여기까지 return 값
  <ul class='comment-row' data-index="1">
    <li class='comment-id'>web7722</li>
    <li class='comment-content'>asdf</li>
    <li class='comment-date'>2022-11-16</li>
  </ul>
  */

  return ul;
}

function drawing() {
  commentList.innerHTML = "";
  for (let i = state.length - 1; i >= 0; i--) {
    const row = createRow(i);
    commentList.append(row);
  }
}

function submitHandler(e) {
  e.preventDefault();

  const form = e.target; // e.target은 form element이기에 이 사실을 보다 직관적으로 볼 수 있도록 form 변수에 담아줌!!
  const value = form.content.value;
  // e.target.content // Element
  // console.log(e.target.content.value); // 출력 확인용

  // const instance = new Comment(value);
  // state.push(instance);
  // console.log(state); // 출력 확인용

  // try 구문은 throw를 통해 에러를 던져주는지 체크하는 역할을 수행하며, 만일 throw를 통해 에러를 던질 시에는 try 문을 거기서 종료하고 catch 문을 실행시킴!!
  try {
    const instance = new Comment(value);
    addComment(instance);
    drawing();
  } catch (error) {
    // (중요!!) catch 문의 "error" 매개변수는 객체이다!!
    alert(error.message);
    console.log(error);
  }
  form.content.focus();
  totalRecord();
  e.target.reset();
}

function clickHandler(e) {
  /*
  //   if (e.target.className === "comment-content") {
  //     // console.log("hello world!", e.target);
  //     console.log(e.target.innerHTML);
  //     console.dir(e.target.parentNode.dataset.index);
  //   }

  // 바로 위의 if 문과 동일하게 동작하지만 반대로 조건을 설정하여 코드블록을 벗겨내고 return으로 받았기에 코드 형태가 더 좋음!!
  if (e.target.className !== "comment-content") return;
  console.log(e.target.innerHTML);
  console.dir(e.target.parentNode.dataset.index);

  const value = e.target.innerHTML;
  e.target.innerHTML = "";
  const input = document.createElement("input");
  input.value = value;
  e.target.append(input);
  */

  console.log(e.target);
  if (e.target.className === "comment-content") {
    const index = parseInt(e.target.parentNode.dataset.index);
    state[index].updated = true;
    // state[index].updated = !state[index].updated; // 이렇게 하면 content 내용을 클릭할 때마다 true, false가 번갈아가면서 바뀜!!
    state[index].updateValue = state[index].content;
    drawing();
  } else if (e.target.className === "comment-delete-btn") {
    const index = parseInt(e.target.parentNode.parentNode.dataset.index);
    state.splice(index, 1);
    totalRecord() - 1;
    drawing();
  }

  if (e.target.className !== "comment-content") return;
}

commentList.addEventListener("click", clickHandler);
commentFrm.addEventListener("submit", submitHandler);


/*
// 함수 선언문
function comment1() {

}

// 생성자 함수와 class는 객체 리터럴 문법과 더불어 객체를 찍어낼 때 사용하는 방법임!!
// 생성자 함수
// 생성자 함수의 경우, new 키워드를 써서 새로 객체를 생성할 시 아래와 같이 "this = {}", "return this"가 생략되어 있다고 보면 됨!!
function Comment2() {
    // this = {}
    // return this
}

// class
class Comment() {
    constructor() {

    }
}

new Comment()

// 생성자 함수와 class의 차이(우리가 class를 사용하는 이유)
// class는 생성 시 new 키워드를 사용하지 않으면 에러를 표시함(객체 생성이라는 용도가 확실함), 또한 class는 호이스팅을 발생시키지 않음!!
// 생성자 함수는 생성 시 new 키워드를 사용하지 않아도 에러를 표시하지 않고 함수 실행이 정상적으로 됨(function 키워드는 용도가 모호함), 또한 생성자 함수는 호이스팅을 발생시킴!!
// 따라서 객체 생성을 위해서 생성자 함수를 사용할 일이 있다면 가급적 class를 사용하는 것이 코드 가독성(class는 용도가 확실함!!) 측면을 고려했을 때 더 좋다!!
*/

 

 

 

 

 

1-2) 게시판 기초

JSON

console.log(a);
console.log(person);

/*
다른 js 파일(list.js)에서 선언한 a와 person 둘 다 출력이 안 됨!!
>> 이는 데이터 공유가 안 되기 때문!!
>> a와 person 변수는 list.js에 선언되어 있기에 write.js에서는 공유할 수 없음!!
*/

// 그럼 데이터 공유를 하려면 방법이 전혀 없을까?
// 이에 데이터 공유는 안되지만 "get, post"를 써서 데이터를 넘길 수 있다!

// 웹 페이지가 느려지면 cookie를 지워 속도를 높이는 경우가 많다!
// cookie

// 브라우저가 데이터(text 파일)를 저장하는 공간이 있음!!

// 브라우저는 데이터를 저장하는데 여기서 데이터란 글자를 의미한다!!
// window.document.cookie(); >> 보는 바와 같이 window가 앞에 달렸다는 것은 브라우저가 cookie를 만들었다는 뜻이다!!
document.cookie = "name=sangbeom";

// localstorage : 데이터 용량

const person = {
name: "sangbeom",
age: 27,
};

console.log(person); // {name:"sangbeom", age:27}

// Object를 똑같이 생긴 String으로 바꿔주는 코드
const person2 = JSON.stringify(person); // "JSON.stringify()"은 인수로 넣은 객체(person)를 string으로 바꿔서 return해 줌!!

console.log(person2); // {"name":"sangbeom","age":27}

// typeof
console.log(typeof person); // object
console.log(typeof person2); // string

const str = '{"name":"sangbeom","age":27}';

console.log(person2 === str); // true

const person3 = JSON.parse(person2); // ""
console.log(person3); // object

// 페이지가 바뀔 때마다 데이터 공유가 안 되기에 파일을 사용해 브라우저에 맡김!!

// list [{}, {}]
// view {}

// localStorage, JSON.parse, get 등을 융합하여 활용할 계획!!

 

 

List

// List
// 형 변환
// Object -> String
// String -> Object


/*
웹 스토리지
- 로컬 스토리지(localStorage): 직접 삭제하기 전까지는 삭제가 안 됨! >> 따라서 우리는 이것을 사용할 예정!
- 세션 스토리지(sessionStorage): 브라우저를 종료하면 사라짐!

쿠키(용량 : 4KB)
- 쿠키는 데이터를 저장하는 용량이 적음!!
*/


// localStorage는 기본적으로 window 객체 안에 있다!!
window.localStorage.setItem('name', 'sangbeom')
window.localStorage.getItem('name')


// write에서 key를 등록해보기

/*
번호
제목
내용
작성자
작성일
조회수
*/

{
	index: 0,
	subject: '',
	content: '',
	writer: '',
	date: '',
	hit: ''
}

 

 

게시판

/*
게시판은 Read가 2개의 형태를 가지기에 CRUD 구현 시 화면이 총 5개가 필요하다!!
- Read의 2가지 형태 - 데이터 전체 표현, 1개(전체의 부분요소 하나를 의미) 표현
- 화면의 경우, html 페이지가 지금까지 만든 것은 모두 한 개였다!!
*/


/*
<게시판 구현에 필요한 페이지>
- 리스트
- 글쓰기
- 글수정
- 글보기
- 글삭제


|-- index.html (http://127.0.0.1:5500/index.html)
|-- board
|---- list.html (http://127.0.0.1:5500/board/list.html)
|---- write.html (http://127.0.0.1:5500/board/write.html)
|---- modify.html (http://127.0.0.1:5500/board/modify.html)
|---- view.html (http://127.0.0.1:5500/board/view.html)
|---- delete.html (http://127.0.0.1:5500/board/delete.html)
*/


/*
유튜브와 같이 페이지는 하나지만 element를 조작(화면을 이동 시 해당 화면에서 바뀔 부분만 element로 만들어 갈아끼우는 개념)하여 페이지를 바꾸는 것을 "SPA(Single Page Application)"라 한다!!
- SPA : Vue, React
*/


/*
경일게임아카데미 기준

메인페이지 - http://www.kiweb.or.kr/index.html
인사말 - http://www.kiweb.or.kr/college/introduction.html
연혁 - http://www.kiweb.or.kr/college/history.html

수강후기 - http://www.kiweb.or.kr/community/review.html
수강후기(view) - http://www.kiweb.or.kr/community/review.html?mode=view&tname=postscript&idx=6872&page=1&keyfield=&keystring=
수강후기(write) - http://www.kiweb.or.kr/community/review.html?mode=write&tname=postscript
*/

 

 

 

 

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>
      <a href="/index.html">로고</a>
    </h1>
    <a href="./board/list.html">게시판 리스트로 가기</a>
    <script src="./public/js/index.js" type="text/javascript"></script>
  </body>
</html>

 

 

list.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>
      <a href="/index.html">로고</a>
    </h1>
    <h2>게시판 리스트</h2>
    <table border="1">
      <thead>
        <tr>
          <td>번호</td>
          <td>제목</td>
          <td>작성자</td>
          <td>등록일</td>
          <td>조회수</td>
        </tr>
      </thead>
      <tbody></tbody>

      <!-- <tr>
        <td>1</td>
        <td><a href="/board/view.html?index=0">글 제목1</a></td>
        <td>황상범</td>
        <td>2022-11-17</td>
        <td>0</td>
      </tr> -->
    </table>
    <a href="/board/write.html">글쓰기</a>

    <script src="../public/js/list.js" type="text/javascript"></script>
  </body>
</html>

※ "board" directory 안의 "write.html" 파일로 a 태그를 사용하여 페이지 이동 링크를 걸어 놓으려 할 경우,

"write.html"이 "list.html"과 동일하게 "board" directory를 상위 폴더로 가리키고 있다면

"/board/write.html"로 작성해야 "write.html"을 제대로 불러올 수 있음!!

만일 "./board/write.html"로 페이지 이동 링크(a 태그)를 걸었다면 이는 "board" directory 안의 또 하나의 "board" directory 내부의 "write.html"을 가져오라고 코드를 인식하기 때문에 결국 잘못된 위치에서 "write.html"을 가져오려 해서 앞의 페이지 이동 링크가 제대로 구현되지 못 함!!

 

 

write.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>
      <a href="/index.html">로고</a>
    </h1>
    <h2>게시판 쓰기</h2>

    <form id="writeFrm">
      <div>제목 : <input type="text" name="subject" /></div>
      <div>작성자 : <input type="text" name="writer" /></div>
      <div>내용 : <textarea name="content"></textarea></div>

      <input type="submit" value="글작성" />
    </form>
    <script src="../public/js/write.js" type="text/javascript"></script>
  </body>
</html>

 

 

view.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>
      <a href="/index.html">로고</a>
    </h1>
    <h2>게시판 쓰기</h2>

    <form id="viewFrm">
      <div id="subject">제목 :<span></span></div>
      <div id="writer">작성자 :<span></span></div>
      <div id="date">작성일 :<span></span></div>
      <div id="content">내용 :<span></span></div>

      <a href="/board/write.html">뒤로 가기</a>
      <a href="/board/list.html">리스트로 가기</a>
    </form>
    <script src="../public/js/view.js" type="text/javascript"></script>
  </body>
</html>

 

 

list.js

/*
let a = "sangbeom";
console.log(a);

const person = {
  name: "sangbeom",
  age: 27,
};

console.log(document.cookie); // 원래대로라면 해당 코드는 출력이 안되어야 하지만 "name=sangbeom"을 출력함
// >> 이는 cookie를 통해 브라우저가 가진 directory에서 특정 파일을 생성하기에 cookie에 값으로 넣은 데이터를 넘기는 것이 가능해짐!!
*/

// boards 있니

let item = localStorage.getItem("boards");
if (item === null) {
  const initialState = [];
  const state = JSON.stringify(initialState);
  localStorage.setItem("boards", state);
  item = state;
}

const tbody = document.querySelector("tbody");

function template(item, index) {
  return `
  <tr>
       <td>${index + 1}</td>
       <td><a href='/board/view.html?index=${index}'>${item.subject}</a></td>
       <td>${item.content}</td>
       <td>${item.date}</td>
       <td>${item.hit}</td>
  </tr>
`;
}

// const obj = { index: 0, subject: "11", content: "11", date: "11", hit: 0 };

// tbody.innerHTML = template(obj);
// console.log(item)

const boards = JSON.parse(item);
// [{}, {}, {}]

for (let i = 0; i < boards.length; i++) {
  tbody.innerHTML += template(boards[i], i);
}

// item = localStorage.getItem("boards");

 

 

write.js

// (중요!!) 데이터의 공유가 안되기 때문에 데이터를 넘기는 것이다!!
// 이때 데이터를 넘겨주는 method는 "get"이다!!
// 브라우저는 데이터(텍스트)에 이름(파일명)을 새겨 저장한다!!

const writeFrm = document.querySelector("#writeFrm");

class Board {
  constructor(subject, content, writer) {
    this.index = 0;
    this.subject = subject;
    this.content = content;
    this.writer = writer;
    this.date = "2022-11-17";
    this.hit = 0;
  }
}

function submitHandler(e) {
  e.preventDefault();
  const subject = e.target.subject.value;
  const content = e.target.content.value;
  const writer = e.target.writer.value;
  const instance = new Board(subject, content, writer);

  // '[]' -> []
  // boards -> []
  // boards.push(instance)
  const boards = JSON.parse(localStorage.getItem("boards"));
  boards.push(instance);
  // console.log(boards);

  const index = boards.length - 1;

  const item = JSON.stringify(boards);
  //   boards: []
  localStorage.setItem("boards", item);
  //   [] -> {}
  e.target.reset();

  // location : html의 a 태그 없이 자바스크립트만으로 링크 이동이 가능하게 하는 객체(location: url과 관련된 내용을 담고 있는 객체)
  location.href = "/board/view.html?index=" + index;
}
writeFrm.addEventListener("submit", submitHandler);

/*
{
    index: 0,
    subject: '',
    content: '',
    writer: '',
    date: '',
    hit: ''
}
*/

// search : window.location 객체 안에 있으며, url에서 ?와 그 이후의 내용, 즉 query string을 가져오는(담고 있는) 객체

(중요!!) 데이터의 공유가 안되기 때문에 데이터를 넘기는 것이다!!
이때 데이터를 넘겨주는 method는 "get"이다!!
브라우저는 데이터(텍스트)에 이름(파일명)을 새겨 저장한다!!

localStorage는 cookie와 동일한 개념(저장 공간)이지만 단지 데이터 용량에서 차이가 있을 뿐이다(localStorage의 데이터 용량이 cookie 보다 크다)!!

 

웹 스토리지
- 로컬 스토리지(localStorage): 직접 삭제하기 전까지는 삭제가 안 됨! >> 따라서 우리는 이것을 사용할 예정!
- 세션 스토리지(sessionStorage): 브라우저를 종료하면 사라짐!

쿠키(용량 : 4KB)
- 쿠키는 데이터를 저장하는 용량이 적음!!

localStorage는 기본적으로 window 객체 안에 있다!!

// 데이터를 입력하고자 할 시에는 setItem을 호출하면 되는데 이때 첫 번째 인자값에는 속성의 key 값을, 두 번째 인자값에는 value 값(string 데이터 타입만 입력 가능!!)을 넣어주면 됨!!
window.localStorage.setItem('name', 'sangbeom')

// 데이터를 가져오고자 할 때는 속성의 key 값만 인자값에 넣어 getItem을 호출하면 됨!!
window.localStorage.getItem('name')

 

 

view.js

const item = window.localStorage.getItem("boards"); // 여기서 item의 데이터 타입: string

// console.log(item); // 출력 결과가 string이기에 object로 형변환 후 해당 객체 안의 특정 값을 가져올 수 있음!!

const boards = JSON.parse(item); // item(string 데이터 타입)을 object로 형변환한 뒤 boards 변수에 item을 할당함!!
// console.log(boards); // object

// console.log(boards.index);
// console.log(boards.subject);
// console.log(boards.content);
// console.log(boards.writer);
// console.log(boards.date);
// console.log(boards.hit);

const idx = location.search.split("="); // 데이터 타입이 string이다!! >> '?index=3' >> ['?index', '3']
const index = idx[1];
const board = boards[index];

const viewFrm = document.querySelectorAll("#viewFrm > div");

for (let i = 0; i < viewFrm.length; i++) {
  const id = viewFrm[i].id; // element의 id 값('subject')
  // board[i] -> board['subject']

  // console.log("id", id, board[id]);
  const span = viewFrm[i].querySelector("span");
  span.innerHTML = board[id];
}