[Project] Webucks Clone Coding #4 [커피 상세 페이지 기능 구현]

📍 What About?


💡 그동안 배운 `HTML`과 `CSS`, 그리고 `JavaScript`를 활용한 위코드 첫 프로젝트가 주어졌다. 프론트엔드 역량을 다지기 위해 스타벅스 페이지를 클론하면서 `HTML`과 `CSS`의 개념을 웹 페이지 개발에 적용하고, JavaScript` 기능을 구현하는 것을 목표로 하며, 별개의 학습 목표도 주어졌다.

⚡️ 학습 목표


  1. HTML 태그를 적절하게 사용하여 페이지 레이아웃을 스스로 구현할 수 있다.
  2. CSS 기초 개념을 활용하여 원하는 디자인을 요소에 적용할 수 있다.
  3. 개발자 도구를 활용하여 실제 페이지 레이아웃의 구성과 적용된 스타일을 확인할 수 있고 필요한 정보를 얻을 수있다.
  4. 로그인 기능을 구현하며 input 태그 활용법에 대해 익힌다.
  5. 과제에서 JavaScript로 여러 기능을 구현하여 DOM의 요소를 조작할 수 있다.
  6. 기본적인 git flow를 이해하고 PR을 작성하여 github을 통한 코드 리뷰 방식을 이해한다.

🌈 My Thoughts

그 동안 배운 HTML, CSS 의 학습내용을 모두 이용해서 Starbucks 홈페이지와 유사한 웹페이지를 만들고, JavaScript을 구현하여 기능들을 구현하는 프로젝트였으며, 드디어 공부한 내용을 활용하여 프로젝트를 할 수 있다는 생각에 신나기까지 했다. 프론트엔드에서 HTML,CSS,JavaScript는 초반부이며 전반적인 내용이지만, 프로젝트를 진행하면서 내가 부족한 부분이나 미숙한 부분을 점검하면서 더 성장할 기회를 준 시간이었던 것 같다. 이 글을 작성하는 시점은 모든 프로젝트의 내용 구현을 마친 후에 내 자신을 돌아보기 위한 회고록이자 프로젝트에 모든 내용과 나 자신을 되돌아 보기 위한 피드백이기도 하다.


📲 커피 상세 페이지 레이아웃 구현

이전 단계에서 구현한 레이아웃에 JavaScript를 통해 좋아요(하트) 버튼과 '엔터를 통한 댓글 입력' 기능을 구현하는 단계이다. 그 동안 배운 JavaScript 학습 내용을 점검하면서 활용할 수 있는 본격적인 단계이며, JavaScript의 부족한 점을 돌아볼 수 있는 단계였다. 리뷰 댓글 삭제와 리뷰별 좋아요 버튼 기능은 다음 단계의 내용이지만, 모두 구현한 상태기도 하며 나 역시 구현할 때 포괄적으로 구현하였기 때문에 함께 수행하였으며 코드에도 적용이 되있다.

🐳 My Code


<HTML>

<!doctype html>
<html>

<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>list</title>
    <link href="styles/detail.css" rel="stylesheet" type="text/css" />
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css"
        integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm" crossorigin="anonymous">
    <link href="https://fonts.googleapis.com/css2?family=Dancing+Script&display=swap" rel="stylesheet">
</head>

<body>
    <nav> <!--최상단의 배너-->
        <div class="menu">
            <a href="" class="logo">Webucks</a>
            <ul>
                <li><a href="" class="menu-list">COFFEE</a></li>
                <li><a href="" class="menu-list">MENU</a></li>
                <li><a href="" class="menu-list">STORE</a></li>
                <li><a href="" class="menu-list">WHAT'S NEW</a></li>
            </ul>
        </div>
    </nav>

    <section> <!--중반부의 레이아웃-->

        <div class="container" id="one"> <!-- 중반부 전체를 감싸는 div 태그-->
            
            <div class="first"> <!--중반부 를 두개의 div태그로 나누어 왼쪽 절반의 구역으로 나눠줌-->
                <p class="coldbrew">콜드 브루</p>
                <img src="coffeedetailpage.PNG" alt="콜드브루">
            </div>

            <div class="second"> <!--중반부 를 두개의 div태그로 나누어 오른쪾 절반의 구역으로 나눠줌-->
                    <br>
                    <p class="gray">홈 > MENU > 음료 > 에스프레소 > 화이트 초콜릿 모카</p>

                    <div id="fifth">
                        <div class="emojiright">
                            <p class="coffeename">화이트 초콜릿 모카</p>
                            <p class="coffeename2">White Chocolate Mocha</p>
                        </div>
                        <div id="heart2">
                            <a href="#"><i class="far fa-heart" id="heart3"></i></a>
                        </div>
                    </div>

                    <p class="seconddetail">달콤하고 부드러운 화이트 초콜릿 시럽과 에스프레소를 스팀 밀크와 섞어
                        휘핑크림으로 마무리한 음료로 달콤함과 강렬한 에스프레소가 부드럽게 어우러진 커피</p>

                    <div class="productdetail">
                        <span>제품 영양 정보</span>
                        <span>Tall(톨) / 355ml (12 fl oz)</span>
                    </div>

                    <div class="productdetail2"> <!--영양정보를 담아주는 div 태그-->
                        <div class="boxone"> <!--영양 정보를 좌우로 반반 나눠주었으며, 왼쪽에 해당하는 div 태그-->
                            <ul>
                                <li>
                                    <span class="l">1회 지공량(kcal)</span>
                                    <span>345</span class="r">
                                </li>
                                <li>
                                    <span class="l">포화지방 (g)</span>
                                    <span>11</span class="r">
                                </li>
                                <li>
                                    <span class="l">단백질 (g)</span>
                                    <span>11</span class="r">
                                </li>
                            </ul>
                        </div>

                        <div class="boxtwo"> <!--영양 정보를 좌우로 반반 나눠주었으며, 오른쪽에 해당하는 div 태그-->
                            <ul>
                            <ul>
                                <li>
                                    <span class="l">나트륨(mg))</span>
                                    <span>150</span class="r">
                                </li>
                                <li>
                                    <span class="l">당류 (g)</span>
                                    <span>35</span class="r">
                                </li>
                                <li>
                                    <span class="l">카페인 (mg)</span>
                                    <span>75</span class="r">
                                </li>
                            </ul>
                        </div>

                    </div>

                    <div class="allegy">알레르기 유발 요인 : 우유</div>

                    <p class="reviewnav">리뷰</p>

                    <div class="Allcomment"> <!--모든 댓글 내용을 담아내는 div 태그-->
                        <div class="comment"> <!-- comment class는 각각 하나의 댓글을 담아냄 -->
                            <span class="id">coffee_lover</span>
                            <span class="ment">너무 맛있어요!</span>
                            <button class="deletebutton">삭제</button>
                            <a href="#" class="commentheart"><i class="far fa-heart"></i></a>
                        </div>

                        <div class="comment">
                            <span class="id">CHOCO7</span>
                            <span class="ment">오늘도 화이트 초콜릿 모카를 마시러 갑니다</span>
                            <button class="deletebutton">삭제</button>
                            <a href="#" class="commentheart"><i class="far fa-heart hearts"></i></a>
                        </div>

                        <div class="comment">
                            <span class="id">legend_dev</span>
                            <span class="ment">진짜 화이트 초콜릿 모카는 전설이다.
                                진짜 화이트 초콜릿 모카는 전설이다.
                                진짜 화이트 초콜릿 모카는 전설이다.
                            </span>
                            <button class="deletebutton">삭제</button>
                            <a href="#" class="commentheart"><i class="far fa-heart"></i></a>
                        </div>
                    </div>

                    <input text="" placeholder="리뷰를 입력해주세요" class="reviewcomment"
                            onkeyup="if(window.event.keyCode==13){test()}"> <!--후반부에 구현할 댓글 입력을 위한 input 태그-->
    </section>
    
    <footer> <!-- 최하단부의 배너를 담는 fotter 태그 -->
    <div class="bottomzone">
        <div>
            <p>COMPANY</p>
            <ul>
                <li>한눈에 보기</li>
                <li>스타벅스 사명</li>
                <li>스타벅스 소개</li>
                <li>국내 뉴스룸</li>
                <li>세계의 스타벅스</li>
                <li>글로벌 뉴스룸</li>
            </ul>
        </div>

        <div>
            <p>CORPORATE SALES</p>
            <ul>
                <li>단체 및 기업 구매 안내</li>
            </ul>
        </div>

        <div>
            <p>PARTNERSHIP</p>
            <ul>
                <li>신규 입점 제의</li>
                <li>협력 고객사 등록 신청</li>
            </ul>
        </div>

        <div>
            <p>ONLINE COMMUNITY</p>
            <ul>
                <li>페이스북</li>
                <li>트위터</li>
                <li>유튜브</li>
                <li>블로그</li>
                <li>인스타그램</li>
            </ul>
        </div>

        <div>
            <p>RECRUIT</p>
            <ul>
                <li>채용 소개</li>
                <li>채용 지원하기</li>
            </ul>
        </div>

        <div>
            <p>WEBUCKS</p>
        </div>

    </div>
    </footer>

</body>

<script src="js/detail.js">
</script> <!--후반부의 기능들을 구현하기 위한 js 코드-->

</html>

<JavaScript>

 const heart = document.getElementById("heart3"); //오른쪽 상단의 하트 버튼 기능 구현
function hearts() {
    if (heart.style.fontWeight != "bold") {
        heart.style.fontWeight = "bold";
    }
    else {
        heart.style.fontWeight = "normal";
    }
}
heart.addEventListener("click", hearts);


//원래 있던 세개의 댓글 내에 하트 기능 추가.
let commentHeart = document.getElementsByClassName("commentheart"); 
for (let i = 0; i < commentHeart.length; i++) {
    commentHeart[i].addEventListener("click", () => {
        if (commentHeart[i].innerHTML === '<i class="far fa-heart"></i>') {  
            commentHeart[i].innerHTML = '<i class="fas fa-heart"></i>';
        } // 조건에 따라 하트 아이콘(각각 내부가 채워진 아이콘과 내부가 비워진 하트 아이콘) innerHTML로 지정
        else {
            commentHeart[i].innerHTML = '<i class="far fa-heart"></i>';
        }
    });
}

let deleteButton = document.getElementsByClassName("deletebutton"); 
let deleteComment = document.getElementsByClassName("comment");
for (let i=0; i<deleteButton.length; i++)
{
    deleteButton[i].addEventListener("click",()=>{
        items.removeChild(deleteComment[i]);
    });
} // 원래 존재하던 3개의 댓글 삭제창 구현







let input = document.getElementsByClassName("reviewcomment")[0]; //인풋 창을 칭하는 div 태그
let items = document.getElementsByClassName("Allcomment")[0]; //전체 댓글을 포괄하는 div tag

const onAdd = () => {          //엔터시에 추가되는 댓글 기능 구현  
    const text = input.value;
    if (input.value === '') {
        input.focus();
        return;
    }

    const comment = document.createElement("div"); //한 개의 댓글 (아이디와 멘트 포함)
    comment.setAttribute('class', 'comment');

    const spanMent = document.createElement('span'); // 댓글의 멘트
    spanMent.setAttribute("class", 'ment');
    spanMent.innerHTML = text;

    const spanID = document.createElement('span'); //댓글 작성자의 아이디
    spanID.setAttribute('class', 'id');
    spanID.innerHTML = "G-DRAGON";

    const itemDel = document.createElement('button'); // 삭제 버튼과 그 기능
    itemDel.setAttribute("class", "deletebutton");
    itemDel.innerHTML = "삭제";
    itemDel.addEventListener('click', () => {
        items.removeChild(comment);
    });
    
    const itemHeart = document.createElement("a"); //만들어지는 댓글의 하트 버튼과 그 기능
    itemHeart.setAttribute("href","#");
    itemHeart.setAttribute("class","commentheart");
    itemHeart.innerHTML='<i class="far fa-heart"></i>';
    itemHeart.addEventListener("click",()=> {
        if (itemHeart.innerHTML === '<i class="far fa-heart"></i>') {
            itemHeart.innerHTML = '<i class="fas fa-heart"></i>';
        }
        else {
            itemHeart.innerHTML = '<i class="far fa-heart"></i>';
        }
    });

    comment.appendChild(spanID);
    comment.appendChild(spanMent);
    comment.appendChild(itemDel);
    comment.appendChild(itemHeart);  //아이디와 멘트, 삭제 버튼, 하트 버튼을 comment div 태그 내에 추가해준 후
    items.appendChild(comment);  // 그 comment를 items(전체 댓글을 감싸는 div태그 내에 추가해주어 맨 아래에 댓글이 추가되도록 해줌)
    input.value = '';  // 댓글 입력창을 비워줌
    input.focus();  // 댓글 입력창에 포커스를 넣어줌
};

input.addEventListener('keypress', (event) => { // 댓글 input 창에 enter 키가 눌러졌을 때, onAdd()기능 실현해줌
    if (event.key === 'Enter') {
        onAdd();
    }
    return;
});

📲 구현 화면


⛳️ 회고

JavaScript를 본격적으로 처음 활용한 프로젝트였다. 분명 머릿속에는 "이렇게 구현해서 이렇게 적용하면 되겠군!" 이라는 생각을 가지고, 코딩을 시작해보았지만, "근데 그 구현을 어떤 함수를 사용하는 거지..?" 하며 발 동동 구르고 있는 나 자신을 확인하고 있었다. 내가 모르는 함수와 메소드들도 분명 있었겠지만, 내 학습량과 공부 방법이 어느 정도는 문제가 있었다고 생각한다. 곧바로 JavaScript 레플릿 문제들을 하나하나 다시 복습하고 또 복습하였다.
이 단계에서 주된 피드백은 .getElementById, getElementsByClassName등의 개념이었다. 전자는 단일적인 id를 불러오기 때문에 하나의 객체를 가지며, 후자는 class네임을 가지는 다수의 배열을 담는 객체를 가지기 때문에 []를 통해 index를 부여해주어야 하며, 이를 템플릿으로 찍어주는 과정을 for문을 통해 간결하게 수행하여 적용할수 있다는 게 매우 큰 장점이며 나에게 큰 배움을 주었다.
또한 .innerHTML 을 통해 태그 내 내용을 모두 바꿔줌을 통해 하트 아이콘을 상황에 따라 변경해줄 수 있다는 것 역시 매우 큰 고찰을 주었다.. 별 거 아닐 수도 있지만 이러한 기능을 무수히 많은 요구에서 이뤄낼 수 있다고 생각 들었고, 나에게 큰 피드백을 주었다.
최종적으로 이 프로젝트에서 내게 가장 큰 배움은 .removeChild(), createElement(), setAttribute(), appendChild() 이 네개의 method를 배우고 활용하는 법을 알았다는 것이라고 해도 과언이 아닐 것이다.. 그 외에도 중요한 method들이 많다지만 이번 프로젝트의 가장 큰 공신이었으며, 가장 큰 배움을 준 method들이었고 나를 더 앞으로 나아갈 수 있게 해준 method들이었다.
특히 .setAttribute()는 내 막혔던 프로젝트를 매우 시원하게 뚫어주었고, 프로젝트의 진행 속도를 한결 빠르게 해주었다. 기능은 attribute와 그의 value를 두개의 인자로 받아 지정해줄 수 있다는 간단한 기능이지만, 정말 큰 도움을 주었다.
부족한 JavaScript를 점검하고 또 점검할 수 있었으며, 나를 역시 더 앞으로 나아가게 해주는 프로젝트였으며, 부족한 단점들을 보완해주는 소중한 과정이었다. 정말 부족한 나 자신이지만, 부족한 점을 보완하고 또 보완하며 더 열심히 공부하며 앞으로 나아갈 것이다.
(긴 글 읽어주셔서 감사합니다!)

좋은 웹페이지 즐겨찾기