#1에서 정리한 로그인 페이지에 이어, westagram cloning project에서 가장 많은 시간을 들인 메인 페이지를 정리한다.
2) 메인 페이지
2) 메인 페이지
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8"/>
<title>Westagram</title>
<link href="main.css" rel="stylesheet"/>
<script src="https://kit.fontawesome.com/b5d94dac67.js" crossorigin="anonymous"></script>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link href="https://fonts.googleapis.com/css2?family=Lobster&display=swap" rel="stylesheet"/>
</head>
<body>
<nav>
<div class="navLogo">
<img alt="Westagram logo image" src="img/insta_logo.png"/>
<h1>Westagram</h1>
</div>
<form class="navSearchForm">
<input type="text" placeholder="검색"/>
<i class="fas fa-search"></i>
</form>
<div class="navIcon">
<img alt="explore icon" src="img/explore.png"/>
<img alt="heart icon" src="img/heart.png"/>
<img alt="profile icon" src="img/profile.png"/>
</div>
</nav>
<main>
<section class="feed">
<article>
<div class="feedHeader">
<div class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1634161906242-43a1d5beef68?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=464&q=80"/>
<div class="userInfoDetail">
<span class="userName">eliz_j_<span>
<span class="description">WeCode - 위코드</span>
</div>
</div>
<i class="fas fa-ellipsis-h"></i>
</div>
<img class="feedImg" alt="feed image" src="img/Cat.JPG"/>
<div class="feedIcon">
<i class="far fa-heart"></i>
<i class="far fa-comment"></i>
<i class="far fa-paper-plane"></i>
<i class="far fa-bookmark"></i>
</div>
<div class="feedBody">
<div class="numberOfLikes">
<img alt="user profile image" src="https://images.unsplash.com/photo-1634161906242-43a1d5beef68?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=464&q=80"/>
<span><b>yeonjeong</b>님 외 <b>10명</b>이 좋아합니다</span>
</div>
<div class="feedText">
<span><b>eliz_j_</b></span>
<span>나만 고양이 없어ㅠㅠ  <a href="">더 보기</a></span>
</div>
<ul class="feedComment">
<li>
<span><b>yeonjeong</b></span>
<span>나도 고양이 없어ㅠㅠ</span>
<button class="deleteBtn">x</button>
</li>
</ul>
<span class="feedUploadTime">1시간 전</span>
</div>
<form class="feedCommentInput" onsubmit="return false;">
<input id="commentInput" type="text" placeholder="댓글 달기..."/>
<button id="uploadBtn" type="button">게시</button>
</form>
</article>
</section>
<section class="main_right">
<section class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1634161906242-43a1d5beef68?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=464&q=80"/>
<div class="userInfoDetail">
<span class="userName">eliz_j_</span>
<span class="description">WeCode - 위코드</span>
</div>
</section>
<section class="story">
<div class="storyTitle">
<h4>스토리</h4>
<span> 모두 보기</span>
</div>
<ul>
<li class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1597024065285-6f47cd40f5d0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80"/>
<div class="userInfoDetail">
<span class="userName">yumyum</span>
<span class="description">20분 전</span>
</div>
</li>
<li class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1597024065285-6f47cd40f5d0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80"/>
<div class="userInfoDetail">
<span class="userName">lalala</span>
<span class="description">1시간 전</span>
</div>
</li>
<li class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1597024065285-6f47cd40f5d0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80"/>
<div class="userInfoDetail">
<span class="userName">pwwwwwww</span>
<span class="description">15시간 전</span>
</div>
</li>
</ul>
</section>
<section class="recommend">
<div class="recommendTitle">
<h4>회원님을 위한 추천</h4>
<span>모두 보기</span>
</div>
<ul>
<li class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1597024065285-6f47cd40f5d0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80"/>
<div class="userInfoDetail">
<span class="userName">yumyum</span>
<span class="description">yoyoyoyo님 외</span>
</div>
<button type="button">팔로우</button>
</li>
<li class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1597024065285-6f47cd40f5d0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80"/>
<div class="userInfoDetail">
<span class="userName">lalala</span>
<span class="description">sumsum님 외</span>
</div>
<button type="button">팔로우</button>
</li>
<li class="userInfo">
<img alt="user profile image" src="https://images.unsplash.com/photo-1597024065285-6f47cd40f5d0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80"/>
<div class="userInfoDetail">
<span class="userName">pwwwwwww</span>
<span class="description">newnew님 외</span>
</div>
<button type="button">팔로우</button>
</li>
</ul>
</section>
<section class="westaInfo">
<ul>
<li>Westagram 정보</li>
<li>·</li>
<li>지원</li>
<li>·</li>
<li>홍보 센터</li>
<li>·</li>
<li>API</li>
<li>·</li>
<li>채용 정보</li>
<li>·</li>
<li>개인정보처리방침</li>
<li>·</li>
<li>약관</li>
<li>·</li>
<li>디렉터리</li>
<li>·</li>
<li>프로필</li>
<li>·</li>
<li>해시태그</li>
<li>·</li>
<li>언어</li>
</ul>
<span class="copyright">© 2019 WESTAGRAM</span>
</section>
</section>
</main>
<script defer src="main.js"></script>
</body>
</html>
HTML Self-Review :)
- 메인페이지에서는 구성요소와 구분되는 지점이 많아
section
태그를 활용해보았다. 하나의 페이지 내에서 섹션을 구분함으로써 각각의 역할을 지정하여 보기에 수월하도록 정리함- 디자인을 위해 요소들이 묶여서 움직여야 할 때는
div
태그를 사용할 수밖에 없었다.- 피드 내 댓글 부분은 추후 구현할 이벤트를 위해
ul
li
태그를 활용하였다.- 유저 이미지 + 유저 이름 + 장소 혹은 문구로 동일한 포맷을 가진 요소들의 경우, 원활한 디자인 구현을 위해 동일한
class
속성을 부여하였다.©
가 copyright을 표현할 수 있는 방식이라는 걸 구글링을 통해 알아냄.
CSS
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: rgb(250,250,250);
}
li {
color: black;
font-size: 15px;
}
ul {
list-style: none;
}
/* user information 공통 적용 부분 */
.userInfo {
display: flex;
align-items: center;
}
.userInfo img {
width: 40px;
height: 40px;
border: 1px solid lightgrey;
border-radius: 50%;
}
.userInfoDetail {
display: inline-block;
margin-left: 10px;
}
.userName {
display: block;
font-weight: bold;
}
.description {
display: block;
color: grey;
font-size: 11px;
}
/* 여기부터 nav 부분 */
nav {
display: flex;
justify-content: space-around;
align-items: center;
position: fixed;
height: 55px;
width: 100%;
padding: 10px, 35px, 5px, 35px;
background-color: white;
border-bottom: 1px solid rgb(241,240,240);
z-index: 1000;
}
.navLogo img {
height: 20px;
padding-right: 15px;
border-right: 2px solid black;
}
.navLogo h1 {
display: inline;
margin-left: 10px;
font-family: 'Lobster', cursive;
font-size: 25px;
}
.navSearchForm {
position: relative;
}
.navSearchForm i {
position: absolute;
left: 82px;
padding-top: 8px;
color: rgb(186,187,189);
font-size: 12px;
}
.navSearchForm input {
width:220px;
height: 28px;
border: 1px solid rgb(219,219,219);
border-radius: 3px;
background-color: rgb(250,250,250);
outline: none;
}
.navSearchForm input::placeholder {
color: rgb(165,165,165);
text-align: center;
}
.navIcon img {
width: 25px;
margin: 0 7px;
}
/* 여기부터 main 부분 */
main {
display: flex;
justify-content: center;
height: 100%;
padding-top: 90px;
margin: 0 50px 40px 50px;
}
/* main 중 feed 노출 부분 */
article {
border: 1px solid rgb(219,219,219);
border-radius: 3px;
background-color: white;
}
.feedHeader {
display: flex;
align-items: center;
position: relative;
padding: 10px;
border-bottom: 1px solid rgb(219,219,219);
}
.feedHeader i {
position: absolute;
right: 15px;
}
.feedImg {
width: 600px;
}
.feedIcon {
display: flex;
align-items: center;
padding: 5px 0;
}
.feedIcon i {
padding-left: 15px;
font-size: 25px;
}
.feedIcon .fa-bookmark {
padding-left: 440px;
}
.feedBody {
display: flex;
flex-direction: column;
margin: 10px 15px;
}
.numberOfLikes {
display: flex;
align-items: center;
}
.numberOfLikes img {
width: 20px;
height: 20px;
border: 1px solid lightgrey;
border-radius: 50%;
}
.numberOfLikes span {
padding-left: 8px;
}
.feedText {
margin-top: 10px;
line-height: 30px;
}
.feedText a {
text-decoration: none;
}
.feedComment {
position: relative;
}
.feedComment .deleteBtn {
position: absolute;
right: 12px;
color: grey;
background-color: white;
border: none;
}
.feedUploadTime {
margin-top: 10px;
color: rgb(148,148,148);
font-size: 12px;
}
.feedCommentInput {
position: relative;
border-top: 1px solid rgb(219,219,219);
}
.feedCommentInput input{
width: 550px;
padding: 15px 10px;
border: none;
outline: none;
}
.feedCommentInput button {
position: absolute;
right: 0px;
width: 50px;
height: 100%;
color: rgb(198,223,250);
background-color: white;
border: none;
}
/* main 중 main-right 노출 부분 */
.main_right {
width: 300px;
margin-left: 30px;
}
.story, .recommend {
margin-top: 15px;
padding: 12px;
border: 1px solid rgb(219,219,219);
border-radius: 3px;
background-color: white;
}
.storyTitle, .recommendTitle {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 14px;
}
.storyTitle h4, .recommendTitle h4 {
color: rgb(144,144,144);
}
.storyTitle span, .recommendTitle span {
font-weight: bold;
}
.story ul, .recommend ul {
display: flex;
flex-direction: column;
}
.story li, .recommend li {
margin-top: 8px;
}
.story .userInfo img {
padding: 2px;
border: 2px solid rgb(200,61,126);
border-radius: 50%;
}
.recommend .userInfo img {
border: 2px solid lightgrey;
border-radius: 50%;
}
.recommend .userInfo {
position: relative;
}
.recommend button {
position: absolute;
right: 0;
border: none;
color: rgb(68,148,239);
background-color: white;
font-weight: bold;
}
.westaInfo {
display: flex;
flex-direction: column;
}
.westaInfo ul {
margin-top: 15px;
}
.westaInfo li {
float: left;
margin: 0 1px;
color: lightgrey;
font-size: 12px;
}
.copyright {
margin-top: 10px;
color: lightgrey;
font-size: 14px;
}
CSS Self-Review :)
긴 코드로 인해 가독성이 너무 떨어지는 것 같아, 주석을 일부 활용하여 구간을 표기하였다.
- 공통적인 디자인이 적용되는 내용은 그냥 적어두니 코드를 다시 볼 때 알아보기가 너무 어려워 코드 앞 부분에 따로 빼서 정리하였다.
nav
부분이 스크롤 할 때 다른 컨텐츠에 가려지는 문제가 발생하여 구글링! 우선순위때문에 발생하는 문제라고 하여 해당 부분에z-index
를 주어 문제를 해결 :)- 이전의 weegle 문제를 풀며
display : flex
와positon
에 대해 고민했던 보람이 있다! 이제는 비교적 수월하게 해당 속성들을 활용 하는 듯.
메인 페이지에서 구현한 이벤트는,
feed 내 댓글을 입력하고 엔터를 치거나 게시버튼을 누르면 댓글이 추가되는 이벤트와,
추가된 댓글 우측의 x 버튼을 누르면 다시 댓글이 삭제되는 이벤트이다.
Javascript
"use strict";
const commentInput = document.getElementById('commentInput');
const uploadBtn = document.getElementById('uploadBtn');
function checkInput () {
const commentValue = commentInput.value;
if(commentValue.length){
addComment(commentValue);
} else {
alert("댓글을 입력해주세요");
}
}
function addComment (value) {
const commentList = document.getElementsByClassName('feedComment')[0];
const newComment = document.createElement('li');
newComment.innerHTML = `<span><b>didoo</b>  <span>${value}</span><span class="deleteBtn">x</span>`;
deleteComment(newComment);
commentList.appendChild(newComment);
commentInput.value = '';
}
function deleteComment (newComment) {
const deleteBtn = newComment.querySelector('.deleteBtn');
deleteBtn.style.cursor = 'pointer';
deleteBtn.addEventListener('click', () => newComment.remove());
}
const init = () => {
uploadBtn.addEventListener('click', checkInput);
commentInput.addEventListener('keydown', () => {
if (window.event.code === 'Enter'){
checkInput();
}
});
}
init();
Javascript Self-Review :)
로그인 페이지에서의 연습으로 게시버튼 클릭 시 댓글 추가되는 것까지는 비교적 수월하게 완성. 하지만 키이벤트에서는 꽤나 고전했는데,addEventListener
안에 함수를 넣고, 해당 함수를 통해checkInput()
을 불러오면서 문제 해결.
해결의 기쁨도 잠시,, 댓글을 삭제하는 이벤트는 더더욱 고전을 면치 못함..
- 추가된 코멘트의 내용을
deleteComment()
함수가 온전히 받아야 하기 때문에addComment()
내에deleteComment()
작성- 다 잘 작성했는데도 작동하지 않아 코드를 살펴보니, 새롭게 생성된
newComment
의 버튼이 아닌 기존 Comment의 버튼을 불러와 그곳에addEventListener
를 부여해서 문제가 생겼던 거였다. 해당 부분을 수정하니 문제 해결! 행복!!!querySelector
는 html 요소를 Javascript로 불러올 때document
보다 더 작은 범위에서 내가 원하는 요소를 찾을 수 있도록 도와준다. 실용적인 방법이니 사용에 익숙해지도록 하자!