오늘은 이전에 만들었던 게시판에 list 페이지와 view 페이지를 만들어 보자!

파일 목록

📦Board
┣ 📂board
┃┣ 📜list.html
┃ ┣ 📜modify.html
┃ ┣ 📜view.html
┃ ┗ 📜write.html
┣ 📂public
┃ ┗ 📂js
┃ ┃ ┣ 📜list.js
┃ ┃ ┣ 📜modify.js
┃ ┃ ┣ 📜view.js
┃ ┃ ┗ 📜write.js
┗ 📜index.html

구현

구현해야 할 사항은 크게 다음과 같다.

  • 게시물 작성하기 (Create)
  • 리스트로 게시물 보여주기 (Read)
  • 게시물 클릭 시 해당 게시물 보여주기 (Read)
  • 게시물 수정하기 (Update)
  • 게시물 삭제하기 (Delete)

게시판 구현하기

게시판 구조

게시판 구조

리스트로 게시물 보여주기 (Read)

# public/js/list.js

현재 리스트 파일의 코드는 다음과 같다.

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

localStrorage에서 boards라는 키를 가진 데이터를 불러오는데 없으면 빈 배열을 boards에 담아 저장하고 있다.

list 페이지는 write 페이지에서 저장한 데이터를 보여주는 페이지이다.

write 페이지에 데이터를 생성한 다음 list.js 파일에서 데이터를 불러오는 작업을 한번 진행해보자!

write 페이지에서 데이터 생성하기

데이터를 생성해 주었다면 list.js 파일에서 localStorage에 저장된 데이터를 가져와보자!

# public/js/list.js

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

const boardsObj = JSON.parse(boardsStr);

console.log(boardsObj);

list.js 파일에서 localStorage의 데이터를 불러온 모습

가져온 데이터를 아래 형태에 맞게 tbody에 넣어 주어야 한다.

<tr>
  <td>번호</td>
  <td>글제목</td>
  <td>작성자</td>
  <td>등록일</td>
  <td>조회수</td>
</tr>

위 형식에 맞는 템플릿을 만드는 함수를 생성해 보자!

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

const boardsObj = JSON.parse(boardsStr);

const template = () => {
  return `
  <tr>
    <td>번호</td>
    <td>글제목</td>
    <td>작성자</td>
    <td>등록일</td>
    <td>조회수</td>
  </tr>
  `;
};

console.log(template());

template함수 실행 결과

template 함수에 두 개의 매개변수를 생성해서 boards의 데이터에 있는 값들이 들어갈 수 있도록 해보자!

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

const boardsObj = JSON.parse(boardsStr);

const template = (index, objValue) => {
  return `
  <tr>
    <td>${index + 1}</td>
    <td>${objValue.subject}</td>
    <td>${objValue.writer}</td>
    <td>${objValue.date}</td>
    <td>${objValue.views}</td>
  </tr>
  `;
};

for (let i = 0; i < boardsObj.length; i++) {
  console.log(template(i, boardsObj[i]));
}

template 함수에서 index와 objValue를 받을 수 있도록 했다.

index는 list 페이지에서 보여줄 데이터의 순서로 실제 boards 안의 index를 의미하지는 않는다.

objValue는 i 값에 해당하는 index에 위치한 boards안에 있는 데이터를 의미한다.

매개변수를 추가한 templage 함수 실행 결과

이제 tbody 요소를 선택한 다음 이 값을 innerHTML을 이용하여 tbody 안에 넣어주면 된다.

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

const boardsObj = JSON.parse(boardsStr);

const template = (index, objValue) => {
  return `
  <tr>
    <td>${index + 1}</td>
    <td>${objValue.subject}</td>
    <td>${objValue.writer}</td>
    <td>${objValue.date}</td>
    <td>${objValue.views}</td>
  </tr>
  `;
};

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

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

list 페이지에 데이터가 잘 출력되는 모습

list 페이지에 원하는 결과가 잘 출력되고 있다.

이번에는 글제목을 클릭하면 해당하는 게시물로 이동할 수 있도록 해보자!

그리고 url에 이게 몇 번째 게시물인지 알 수 있도록 매개변수로 데이터의 인덱스를 넘겨주자!

url에 매개변수를 넘겨주는 이유는 view 페이지에서는 몇 번째 게시물을 클릭해서 들어왔는지 알 수 없기 때문에 url에 매개변수를 넘겨주는 것이다. 

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

const boardsObj = JSON.parse(boardsStr);

const template = (index, objValue) => {
  return `
  <tr>
  <td>${index + 1}</td>
  <td><a href="/board/view.html?index=${objValue.index}">${objValue.subject}</a></td>
  <td>${objValue.writer}</td>
  <td>${objValue.date}</td>
  <td>${objValue.views}</td>
  </tr>
  `;
};

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

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

a 태그의 href 속성을 이용해 페이지를 이동할 수 있도록 하였다. 그리고 해당하는 데이터의 index값도 같이 넘겨주었다.

해당 게시물을 선택하면 url이 바뀌는 모습

쿼리 스트링 (Query String)
쿼리 스트링은 url 부분에 ? 뒤에 붙은 매개변수들로 구성된다.
? 뒤에 붙은 매개변수들은 key=value 형태로 이루어진다. 
자바스크립트에서 전달한 파라미터를 이용하기 위해 window.location 객체를 이용한다.

위에 그림을 보면 해당 게시물을 클릭했을 때 url 부분이 바뀌는 걸 볼 수 있다. 

형태를 살펴보면 다음과 같다.

쿼리 스트링 형태

이제 view 페이지에서 넘겨받은 인덱스 값을 이용해 해당하는 데이터를 보여주는 작업을 해보자!

게시물 클릭 시 해당 게시물 보여주기 (Read)

# public/js/view.js

데이터를 가져오는 작업부터 하자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

console.log(boardsStr);
console.log(boardsObj);

localStorage에서 데이터를 가져와서 원본 형태로 변환한 모습

데이터를 잘 가져왔다면 이번에는 url의 쿼리 스트링을 가져와서 필요한 형태로 만들어보자!

쿼리스트링을 가져오려면 location 객체의 search 속성을 이용하면 된다.

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
console.dir(location);
console.log(idx);

쿼리스트링 가져오기

우리가 필요한 건 index=0에서 0 부분이다.

0 부분을 split 메서드를 사용해 잘라내자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];

console.log(idx);
console.log(idx.split("="));
console.log(index);

필요한 부분을 잘라낸 결과

잘라낸 인덱스를 이용해 원하는 데이터를 출력해보자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

console.log(board);

boards 데이터를 출력한 결과

이제 이 데이터를 위치에 맞게 뿌려주면 된다. 

뿌려줄 위치를 선택해보자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

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

데이터를 출력할 위치를 선택한 모습

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

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

for (let i = 0; i < viewFrm.length; i++) {
  const id = viewFrm[i].id;
  viewFrm[i].innerHTML += " " + board[id];
}

데이터가 잘 출력되는 모습

for 문을 사용해 div 태그의 i번째 id 값을 가져온다.

boards 데이터에 id와 같은 이름을 가진 속성을 선택해 해당하는 값을 i번째 div에 넣어주었다.

[+추가] 조회수 구현

게시물을 클릭하면 조회수가 올라가도록 해보자!

주의해야 할 점은 현재 글을 작성하면 작성한 글을 바로 보여주게 되어있기 때문에 글 작성 직후에는 조회수가 올라가지 않도록 해줘야 한다.

그래서 나는 document.referrer를 사용했다.

document.referrer에는 이전 페이지의 url이 담겨 있기 때문이다. 

직접 한번 확인해 보자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

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

for (let i = 0; i < viewFrm.length; i++) {
  const id = viewFrm[i].id;
  viewFrm[i].innerHTML += " " + board[id];
}

console.log(document.referrer);

이전 페이지인 list.html이 출력되는 모습

이전 페이지의 url을 원하는 형태로 잘라보자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

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

for (let i = 0; i < viewFrm.length; i++) {
  const id = viewFrm[i].id;
  viewFrm[i].innerHTML += " " + board[id];
}

const beforeUrl = document.referrer;

console.log(beforeUrl);
console.log(beforeUrl.split("/"));
console.log(beforeUrl.split("/").pop());

이전 url을 원하는 형태로 자른 모습

이제 이전 페이지가 list.html 일 때만 조회수가 올라갈 수 있도록 코드를 구현해 보자!

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

const beforeUrl = document.referrer;

const viewCount = (beforeUrl) => {
  if (beforeUrl.split("/").pop() === "list.html") {
    board.views++;
    const viewCountStr = JSON.stringify(boardsObj);
    localStorage.setItem("boards", viewCountStr);
  }
};

viewCount(beforeUrl);

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

for (let i = 0; i < viewFrm.length; i++) {
  const id = viewFrm[i].id;
  viewFrm[i].innerHTML += " " + board[id];
}

조회수가 잘 작동하는 모습

Javascript 코드

# public/js/list.js

let boardsStr = localStorage.getItem("boards");

if (boardsStr === null) {
  const listStr = JSON.stringify([]);
  localStorage.setItem("boards", listStr);
  boardsStr = listStr;
}

const boardsObj = JSON.parse(boardsStr);

const template = (index, objValue) => {
  return `
  <tr>
  <td>${index + 1}</td>
  <td><a href="/board/view.html?index=${objValue.index}">${objValue.subject}</a></td>
  <td>${objValue.writer}</td>
  <td>${objValue.date}</td>
  <td>${objValue.views}</td>
  </tr>
  `;
};

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

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

# public/js/view.js

const boardsStr = localStorage.getItem("boards");
const boardsObj = JSON.parse(boardsStr);

const idx = location.search;
const index = idx.split("=")[1];
const board = boardsObj[index];

const beforeUrl = document.referrer;

const viewCount = (beforeUrl) => {
  if (beforeUrl.split("/").pop() === "list.html") {
    board.views++;
    const viewCountStr = JSON.stringify(boardsObj);
    localStorage.setItem("boards", viewCountStr);
  }
};

viewCount(beforeUrl);

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

for (let i = 0; i < viewFrm.length; i++) {
  const id = viewFrm[i].id;
  viewFrm[i].innerHTML += " " + board[id];
}