본문 바로가기

[연습 프로젝트] 문답 게시판_클라이언트 : 페이지네이션 등

[연습 프로젝트] 문답 게시판_클라이언트 : 페이지네이션 등

결과물 

** 반응형 아님 (모니터 권장)

수정 할 것

  • 페이지네이션 (수정 완료)
  • 페이지 나누기 (수정 완료)
  • + 전반적인 코드정리와 리팩토링 (수정 완료)
  • 답변 렌더링 (취소)

 


 

배치 & 디자인 

사용자 경험을 고려하여 컴포넌트 배치를 바꿔보았다. 이제 display: flex는 껌이구나!

 

clear localStorage

로컬 데이터를 비우는 버튼을 만들어주었다. 

 

페이지네이션

 

더보기
// index.html을 열어서 agoraStatesDiscussions 배열 요소를 확인하세요.
console.log(agoraStatesDiscussions);
let data;
const dataFromLocalStorage = localStorage.getItem("agoraStatesDiscussions");
if (dataFromLocalStorage) {
  data = JSON.parse(dataFromLocalStorage);
} else {
  data = agoraStatesDiscussions.slice();
}

// convertToDiscussion은 아고라 스테이츠 데이터를 DOM으로 바꿔줍니다.
const convertToDiscussion = (obj) => {
  const li = document.createElement("li"); // li 요소 생성
  li.className = "discussion__container"; // 클래스 이름 지정

  const avatarWrapper = document.createElement("div");
  avatarWrapper.className = "discussion__avatar--wrapper";
  const discussionContent = document.createElement("div");
  discussionContent.className = "discussion__content";
  const discussionAnswered = document.createElement("div");
  discussionAnswered.className = "discussion__answered";

  // TODO: 객체 하나에 담긴 정보를 DOM에 적절히 넣어주세요.
  const avatarImg = document.createElement("img");
  avatarImg.src = obj.avatarUrl;
  avatarImg.alt = "avatar of " + obj.author;
  avatarWrapper.append(avatarImg);

  const discussionTitle = document.createElement("h2");
  const titleAnchor = document.createElement("a");
  titleAnchor.href = obj.url;
  titleAnchor.textContent = obj.title;
  discussionTitle.append(titleAnchor);

  const discussionInformation = document.createElement("div");
  discussionInformation.className = "discussion__information";
  discussionInformation.textContent = `${obj.author} / ${new Date(
    obj.createdAt
  ).toLocaleTimeString()}`;
  discussionContent.append(discussionTitle, discussionInformation);

  const checked = document.createElement("p");
  checked.textContent = obj.answer ? "☑" : "☒";
  discussionAnswered.append(checked);

  li.append(avatarWrapper, discussionContent, discussionAnswered);
  return li;
};

// data 배열의 모든 데이터를 화면에 렌더링하는 함수입니다.
const render = (element, from, to) => {
  console.log(from, to);
  if (!from && !to) {
    from = 0;
    to = data.length - 1;
  }
  // 다 지우고 배열에 있는 내용 다 보여주기
  while (element.firstChild) {
    element.removeChild(element.firstChild);
  }
  for (let i = from; i < to; i += 1) {
    element.append(convertToDiscussion(data[i]));
  }
  return;
};

// 페이지네이션을 위한 변수
let limit = 10,
  page = 1;

// ul 요소에 data 배열의 모든 데이터를 화면에 렌더링합니다.
const ul = document.querySelector("ul.discussions__container");
render(ul, 0, limit);

// const getPageStartEnd = (limit, page) => {
//   const len = data.length - 1;
//   let pageStart = Number(page - 1) * Number(limit);
//   let pageEnd = Number(pageStart) + Number(limit);
//   if (page <= 0) {
//     pageStart = 0;
//   }
//   if (pageEnd >= len) {
//     pageEnd = len;
//   }
//   return { pageStart, pageEnd };
// };

// const buttons = document.querySelector(".buttons");
// buttons.children[0].addEventListener("click", () => {
//   if (page > 1) {
//     page = page - 1;
//   }
//   const { pageStart, pageEnd } = getPageStartEnd(limit, page);
//   render(ul, pageStart, pageEnd);
// });

// buttons.children[1].addEventListener("click", () => {
//   if (limit * page < data.length - 1) {
//     page = page + 1;
//   }
//   const { pageStart, pageEnd } = getPageStartEnd(limit, page);
//   render(ul, pageStart, pageEnd);
// });

// buttons.children[2].addEventListener("click", () => {
//   localStorage.removeItem("agoraStatesDiscussions");
//   data = agoraStatesDiscussions.slice();
//   limit = 10;
//   page = 1;
//   render(ul, 0, limit);
// });

// 문서의 내용을 확인해야 합니다.
const form = document.querySelector("form.form");
const author = form.querySelector("div.form__input--name > input");
const title = form.querySelector("div.form__input--title > input");
const textbox = form.querySelector("div.form__textbox > textarea");

// 문서를 제출해야 합니다.
form.addEventListener("submit", (event) => {
  event.preventDefault();
  const obj = {
    id: "unique id",
    createdAt: new Date().toISOString(),
    title: title.value,
    url: "https://github.com/codestates-seb/agora-states-fe/discussions",
    author: author.value,
    answer: null,
    bodyHTML: textbox.value,
    avatarUrl:
      "https://avatars.githubusercontent.com/u/12145019?s=64&u=5c97f25ee02d87898457e23c0e61b884241838e3&v=4",
  };
  data.unshift(obj);

  // 로컬스토리지에 저장
  localStorage.setItem("agoraStatesDiscussions", JSON.stringify(data));

  // 렌더링
  render(ul, 0, limit);
});

 

답변 렌더링(취소)

질문을 클릭하면 화면에 답변까지 렌더링되는 것까지 고려했기 때문에 어떤 식으로 할지 고민을 해 보았다.

 

1. 게시물을 클릭하면 질문 내용 + 답변이 화면의 아래에 크게 뜨도록 한다.

 -> 보통 문답게시판에 오는 사용자들은 여러 질문들을 여러 개 탭을 키워놓고 자료를 찾을 가능성이 높다.

     클릭 한 번에 게시물을 하나만 볼 수 있는 것은 사용자 경험에 고려했을 때 바람직하지 않음 

2. 게시물을 클릭하면 질문 내용 + 답변에 팝업처럼 뜨게 한다.

 -> 1번의 이유와 마찬가지

 

최선의 경우는 클릭했을 때 게시글들이 새 탭으로 뜨게하는 방법이다. 그런 결론을 내었기 때문에 이번 미니 프로젝트에서는 딱히 건들지 않았다. 

 


 

내가 상상하고 원하는 무언가를 디지털 상에 구현할 수 있다는 것 자체가 짜릿하다. 하면 할 수록 빠져든다. 너무 재밌다.. 빨리 나만의 웹앱을 만들 수 있는 날이 오길!

 

728x90
⬆︎