[TIL] 220103

Lee Syong·2022년 1ė›” 3ėž
0

TIL

ëŠĐ록 ëģīęļ°
138/204
post-thumbnail

📝 ė˜Ī늘 한 ęēƒ

  1. ëģĩėŠĩ - COMMENT SECTION

📚 ë°°ėšī ęēƒ (ëģĩėŠĩ)

ė „ėēī ė―”드는 githubė— ė˜ŽëĶž(wetube_v2)

13. COMMENT SECTION

  • [TIL] 211217
    • ė‹Īė‹œę°„ 댓ęļ€ ęĩŽí˜„ (javascript로 댓ęļ€ ėķ”ę°€)
    • textarea 높ėī ėžë™ ėĄ°ė ˆ (ėķ”ę°€)
    • 댓ęļ€ ėž‘ė„ąëž€ íīëĶ­ ė‹œ ėĢžëģ€ ėš”ė†Œë“Ī ėŠĪ타ėž ëģ€ęē― (ėķ”ę°€)
    • ė·Ļė†Œ ëē„튞 & 댓ęļ€ ëē„튞 ęĩŽí˜„ (ėķ”ę°€)
    • 댓ęļ€ ėī 개ėˆ˜ ė‹Īė‹œę°„ ė—…데ėīíŠļ (ėķ”ę°€)

ðŸ’Ą ė‹Īė‹œę°„ 댓ęļ€ ęĩŽí˜„ (javascript로 댓ęļ€ ėķ”ę°€)

🔎 data attribute / JSON.parse()

ėē˜ėŒė—ëŠ” 필ėš”í•œ 값 ė „ëķ€ëĨž data ė†ė„ąėœžëĄœ 만ë“Īė–īė„œ pug 파ėžė— ęļļęēŒ 나ė—īí•ī 프론íŠļė—”ë“œëĄœ 가ė ļė™”ë‹Ī.

div.comment-container__item(data-comment-owner-id=comment.owner._id, data-comment-owner-avatarurl=comment.owner.avatarUrl, data-comment-owner-name=comment.owner.name)

ėīęąī ė•„ë‹Œ ęą° 같ė•„ė„œ data-comment-owner만 ë‚Ļęēžë‹Ī.

div.comment-container__item(data-comment-owner=comment.owner)
ownerNameLink.textContent = commentMixinItem.dataset.commentOwner.name;

ę·ļ런데 ėī렇ęēŒ 하니ęđŒ comment.js 파ėžė—ė„œ data ė†ė„ąė˜ í‚Ī 값ė„ 가ė ļė˜Ž ėˆ˜ę°€ ė—†ė—ˆë‹Ī.
값ė„ 가ė ļė˜Ž ėˆ˜ ėžˆë„록 JSON.parse()ëĨž ėīėšĐí•ī JSON ëŽļėžė—īė„ ė˜ĪëļŒė íŠļ로 바ęŋ”ėĢžė—ˆë‹Ī.

ownerNameLink.textContent = JSON.parse(commentMixinItem.dataset.commentOwner).name;

🔎 ėķ”후ė— ėˆ˜ė •í•  ęēƒ

comment.pugė—ė„œ ęļ°ëģļ ėīëŊļė§€ëŠ” 배폎 후 ėˆ˜ė •í•  ęēƒėīë‹Ī.
comment.jsė—ė„œëŠ” ėžë‹Ļ github avatar만 ęģ ë Ī했ë‹Ī. 로ėŧŽ íī더ė— ė˜ŽëĶ° 프로필 ėīëŊļė§€ëŠ” ęģ ë Ī하ė§€ ė•Šė•˜ë‹Ī.(ė œëŒ€ëĄœ 띄ėš°ë ĪëĐī ęē―로ė— "/"ëĨž ėķ”ę°€í•īė•ž 하ė§€ë§Œ ė—Žęļ°ė„œëŠ” ęĩģėī ęē―ėš°ëĨž 나눠 만ë“Īė§€ ė•Šė•˜ë‹Ī.) ėī 또한 배폎 후 ėˆ˜ė •í•  ęēƒėīë‹Ī.

//- comment.pug
mixin comment(comment)
  div.comment-container__item(data-comment-owner=comment.owner)
    div.show-comment__profile-img
      a(href=`/users/${comment.owner._id}`)
        //- 배폎 후 ėˆ˜ė •í•  ęēƒ (ęļ°ëģļ ėīëŊļė§€ 할ë‹đ)
        if !comment.owner.avatarUrl
          div.profile-img 😎
        else if comment.owner.socialOnly
          div.profile-img(style=`background-image: url("${comment.owner.avatarUrl}");`)
        else
          div.profile-img(style=`background-image: url("/${comment.owner.avatarUrl}");`)
    div.show-comment__data
      a.show-comment__owner-name(href=`/users/${comment.owner._id}`) #{comment.owner.name}
      p.show-comment__text #{comment.text}
// comment.js
const addComment = (commentText) => {
  const itemDiv = document.createElement("div");
  itemDiv.classList.add("comment-container__item");
  // 프로필 ėīëŊļė§€
  const profileImgDiv = document.createElement("div");
  profileImgDiv.classList.add("show-comment__profile-img");
  const profileImgLink = document.createElement("a");
  profileImgLink.setAttribute(
    "href",
    `/users/${JSON.parse(commentMixinItem.dataset.commentOwner)._id}`
  );
  const profileImg = document.createElement("div");
  profileImg.classList.add("profile-img");
  profileImg.style.backgroundImage = `url("${
    JSON.parse(commentMixinItem.dataset.commentOwner).avatarUrl
  }")`; // ėžë‹Ļė€ Github Avatar만 ęģ ë Īí•Ļ (배폎 후 ėˆ˜ė •í•  ęēƒ)
  // ėīëĶ„ & 댓ęļ€ ë‚īėšĐ
  const dataDiv = document.createElement("div");
  dataDiv.classList.add("show-comment__data");
  const ownerNameLink = document.createElement("a");
  ownerNameLink.classList.add("show-comment__owner-name");
  ownerNameLink.setAttribute(
    "href",
    `/users/${JSON.parse(commentMixinItem.dataset.commentOwner)._id}`
  );
  const text = document.createElement("div");
  text.classList.add("show-comment__text");
  // ėĄ°í•Đ 및 ë°°ėđ˜
  profileImgLink.appendChild(profileImg);
  profileImgDiv.appendChild(profileImgLink);
  ownerNameLink.textContent = JSON.parse(
    commentMixinItem.dataset.commentOwner
  ).name;
  text.textContent = commentText;
  dataDiv.appendChild(ownerNameLink);
  dataDiv.appendChild(text);
  itemDiv.appendChild(profileImgDiv);
  itemDiv.appendChild(dataDiv);
  commentContainerShow.prepend(itemDiv);
};

ðŸ’Ą textarea 높ėī ėžë™ ėĄ°ė ˆ

element.scrollHeight ėīėšĐ

// comment.js
const textarea = form.querySelector(".write-comment__textarea");

const textareaResize = (event) => {
  event.target.style.height = "1.5rem";
  event.target.style.height = event.target.scrollHeight + "px";
};

textarea.addEventListener("keyup", textareaResize);

ėī렇ęēŒ ėž‘ė„ąí–ˆëŠ”데 ėē˜ėŒė—” ėīėƒí•˜ęēŒë„ keyup ėīëēĪíŠļ가 ėžė–ī날 때마ë‹Ī textareaė˜ 높ėī가 4pxė”Đ ėĶę°€í–ˆë‹Ī. ė›ėļė€ ė•„래 ė―”ë“œė— ėžˆė—ˆë‹Ī.

.write-comment__textarea:focus {
  border-bottom: 2px solid $color-white;
  transition: all 200ms ease-in-out;
}

í•īë‹đ ė―”ë“œëĨž ė‚­ė œí•˜ęģ  comment.jsė— ë‹ĪėŒ ė―”ë“œëĨž ėķ”ę°€í–ˆë‹Ī.

ðŸ’Ą 댓ęļ€ ėž‘ė„ąëž€ íīëĶ­ ė‹œ ėĢžëģ€ ėš”ė†Œë“Ī ėŠĪ타ėž ëģ€ęē―

// comment.js
const textarea = form.querySelector(".write-comment__textarea");
const submitBtn = document.querySelector(".submit-button");

const TEXTAREA_FOCUS_BG_COLOR = "rgb(168, 218, 220)"; // $color-light-blue
const TEXTAREA_BLUR_BG_COLOR = "rgba(241, 250, 238, 0.4)"; // $color-light-white
const TEXTAREA_FOCUS_COLOR = "rgb(29, 53, 87)"; // $bg
const TEXTAREA_BLUR_COLOR = "rgb(241, 250, 238)"; // $color-dark-white

const handleTextareaValueInput = () => {
  if (textarea.value) {
    submitBtn.style.backgroundColor = TEXTAREA_FOCUS_BG_COLOR;
    submitBtn.style.color = TEXTAREA_FOCUS_COLOR;
  } else {
    submitBtn.style.backgroundColor = TEXTAREA_BLUR_BG_COLOR;
    submitBtn.style.color = TEXTAREA_BLUR_COLOR;
  }
};

const handleTextareaFocus = () => {
  textarea.style.borderBottom = `2px solid ${TEXTAREA_FOCUS_BG_COLOR}`;
};

const handleTextareaBlur = () => {
  textarea.style.borderBottom = `1px solid ${TEXTAREA_BLUR_BG_COLOR}`;
};

textarea.addEventListener("input", handleTextareaValueInput);
textarea.addEventListener("focus", handleTextareaFocus);
textarea.addEventListener("blur", handleTextareaBlur);

ðŸ’Ą ė·Ļė†Œ ëē„튞 & 댓ęļ€ ëē„튞 ęĩŽí˜„

ėœ íŠœëļŒ 댓ęļ€ ėž‘ė„ąëž€ ė°ļęģ í•īė„œ ëđ„ėŠ·í•˜ęēŒ ęĩŽí˜„하ęģ ėž 했ë‹Ī.
ęļ°ëģļė ėœžëĄœ ëē„튞ė€ ëģīėīė§€ ė•Šė§€ë§Œ textarea가 focus 되ëĐī ëē„튞ėī ëģīėīëĐīė„œ textareaė˜ ėŠĪ타ėžėī 바뀐ë‹Ī.
textarea í‚Īëģī드 ėž…ë Ĩ ė—Žëķ€ė— 따띾 '댓ęļ€ ëē„튞'ė˜ ėŠĪ타ėžėī 바뀐ë‹Ī.
댓ęļ€ ëē„튞ė„ 누ëĨīëĐī 댓ęļ€ ėž‘ė„ąëž€ė— ėžˆë˜ ęļ€ė€ ė‚Žëžė§€ęģ  ëŠĻ든 ęēƒė€ ęļ°ëģļ ėŠĪ타ėžëĄœ 바뀌ëĐ° ëē„튞ë“Īėī ė‚­ė œëœë‹Ī.
ė·Ļė†Œ ëē„튞ė„ 누ëĨīëĐī 댓ęļ€ ėž‘ė„ąëž€ė— ėžˆë˜ ęļ€ė€ ė‚Žëžė§€ęģ  ëŠĻ든 ęēƒė€ ęļ°ëģļ ėŠĪ타ėžëĄœ 바뀌ëĐ° ëē„튞ë“Īėī ė‚­ė œëœë‹Ī.
ë‹Īė‹œ textarea가 focus 되ëĐī ëē„튞ë“Īėī ë‹Īė‹œ ėķ”ę°€ë˜ęģ  textareaė˜ ėŠĪ타ėžėī 바뀐ë‹Ī.

// comment.js
let buttonsDiv = document.querySelector(".write-comment__buttons");
let submitBtn = document.querySelector(".submit-button");
let cancelBtn = document.querySelector(".cancel-button");

const TEXTAREA_FOCUS_BG_COLOR = "rgb(168, 218, 220)";
const TEXTAREA_BLUR_BG_COLOR = "rgba(241, 250, 238, 0.4)";
const TEXTAREA_FOCUS_COLOR = "rgb(29, 53, 87)";
const TEXTAREA_BLUR_COLOR = "rgb(241, 250, 238)";

const handleSubmitBtn = async (event) => {
  // ėĪ‘ëžĩ
  if (status === 201) {
    addComment(text);
    handleCancelBtnClick(); // ėķ”ę°€
  }
};

const handleTextareaValueInput = () => {
  if (textarea.value) {
    submitBtn.style.backgroundColor = TEXTAREA_FOCUS_BG_COLOR;
    submitBtn.style.color = TEXTAREA_FOCUS_COLOR;
  } else {
    submitBtn.style.backgroundColor = TEXTAREA_BLUR_BG_COLOR;
    submitBtn.style.color = TEXTAREA_BLUR_COLOR;
  }
};

const handleCancelBtnClick = () => {
  textarea.value = "";
  buttonsDiv.remove();
};

const handleTextareaFocus = () => {
  textarea.style.borderBottom = `2px solid ${TEXTAREA_FOCUS_BG_COLOR}`;
  if (buttonsDiv) {
    form.appendChild(buttonsDiv);
    handleTextareaValueInput(); // ëē„ę·ļ ėˆ˜ė •
  } else {
    buttonsDiv = document.createElement("div");
    buttonsDiv.classList.add("write-comment__buttons");
    cancelBtn = document.createElement("button");
    cancelBtn.classList.add("cancel-button");
    cancelBtn.textContent = "ė·Ļė†Œ";
    submitBtn = document.createElement("button");
    submitBtn.classList.add("submit-button");
    submitBtn.textContent = "댓ęļ€";
    buttonsDiv.appendChild(cancelBtn);
    buttonsDiv.appendChild(submitBtn);
    form.appendChild(buttonsDiv);
  }
  textarea.addEventListener("input", handleTextareaValueInput);
  cancelBtn.addEventListener("click", handleCancelBtnClick);
};

const handleTextareaBlur = () => {
  textarea.style.borderBottom = `1px solid ${TEXTAREA_BLUR_BG_COLOR}`;
};

form.addEventListener("submit", handleSubmitBtn);
textarea.addEventListener("keyup", textareaResize);
textarea.addEventListener("focus", handleTextareaFocus);
textarea.addEventListener("blur", handleTextareaBlur);

â€ŧ ëē„ę·ļ ėˆ˜ė •

textareaė— ęļ€ė„ ė“°ë‹Ī가 formė„ ė œėķœí•˜ė§€ ė•Šęģ  'ė·Ļė†Œ ëē„튞'ė„ 눌럮 ëŠĻ든 ęļ€ėī ė§€ė›Œė§„ 후 ë‹Īė‹œ textarea가 focus 되ëĐī textareaė— ęļ€ėī ė—†ė–ī도 '댓ęļ€ ëē„튞'ęđŒė§€ ėŠĪ타ėžėī ė ėšĐ되ė–ī ėžˆė—ˆë‹Ī.

→ handleTextareaFocus í•Ļėˆ˜ė—ė„œ buttonsDiv가 ė—†ė„ 때 ė•žė„œ 만ë“Īė—ˆë˜ buttonsDivëĨž formė— ėķ”ę°€í•œ 후 handleTextareaValueInput í•Ļėˆ˜ė— ė˜í•ī value 값ė˜ ėĄīėžŽ ėœ ëŽīė— 따띾 '댓ęļ€ ëē„튞' ėŠĪ타ėžėī ė ėšĐ되도록 ėˆ˜ė •í–ˆë‹Ī.

ðŸ’Ą 댓ęļ€ ėī 개ėˆ˜ ė‹Īė‹œę°„ ė—…데ėīíŠļ

//- watch.pug
block content
  div.video-container(data-video=video)
// comment.js
const commentContainer = document.querySelector(".comment-container");
const commentContainerCount = commentContainer.querySelector(".comment-container__count");

const addComment = (commentText) => {
  // ėĪ‘ëžĩ
  commentContainerCount.textContent = `댓ęļ€ ${
    JSON.parse(videoContainer.dataset.video).comments.length + 1 // 플럮ėŠĪ 1 í•īėĪ˜ė•ž í•Ļ
  }개`;
};

📝 ë‚īėž 할 ęēƒ

  1. ëģĩėŠĩ ęģ„ė†í•˜ęļ° - 댓ęļ€ ė‚­ė œ ëē„튞 ėķ”ę°€ / 배폎
  2. textareaė—ė„œ ėž…ë Ĩ한 ėĪ„ 바ęŋˆ ENTER가 ė‹Īė œ ėķ”ę°€ëœ 댓ęļ€ëž€ė—ė„  띄ė–īė“°ęļ°ëĄœ 표ė‹œë˜ëŠ” ëŽļė œ í•īęē°
profile
ëŠĨ동ė ėœžëĄœ ė‚īėž, 행ëģĩ하ęēŒðŸ˜

0개ė˜ 댓ęļ€