티스토리 뷰

 

학교 선배가 데이터를 받아오는 프로젝트를 참고하라고 하시면서

직접 작성한 블로그 링크를 보내주셔서 너무너무 감사했는데...

 

 

코드를 해석하거나 내가 코드를 짜기엔 너무 지식이 없어서(ㅋㅋㅋ ㅠㅠ)

선배에게 무척 죄송하지만 제대로 JS를 공부하는 게 먼저였다.

 

다행히 JS를 하다보니까 재미있고... 실용적인 메소드들을 많이 접해서 여기까지 올 수 있었던 것 같다.

 

아무튼! Json도 긁어왔겠다 fetch도 사용해봤겠다...!

이제 선배가 알려주신 블로그를 조금 이해할 수 있게 돼서 따라해보고자 한다!

아직 React를 제대로 배우지 않았으니 최대한 바닐라 자바스크립트로 작성할 것이당

 

 

 

 

참고한 API 호출 프로젝트는 >>  여기!  <<

 

🛰 API 호출로 프로젝트에 필요한 데이터 GET해오는 방법 (Feat. 프론트앤드, React)

여름이었다 .. 프로젝트 제작을 위해 필요한 데이터가 있다면 API 호출을 통해 받아올 수 있는데 리액트의 경우 JSX 파일 내부에 무작정 자바스크립트 코드(호출을 위한)가 너무 많으면 가독성에

dev-ang.tistory.com

 

 

 

 

 

1. 사이트 방문 & 원하는 데이터 확인

 

선배가 사용한 데이터는 우리 학교 기숙사 식단이다. 

조식이 사라져서... 점심과 석식만이 남아있다...

 

 

 

 

 

 

2. 개발자 도구 (f12) - network 창 확인 & 식단 데이터 찾기

 

식단데이터가 안 떠서 애먹었는데 새로고침을 누르니 해결됐다. (...)

 

그 다음엔 받아올 url을 Headers 섹션에서 확인한다.

 

 

 

 

 

 

 

 

 

 

3. postman 으로 url요청 확인

 

postman이란?

API를 사용한 개발을 도와주는 플랫폼이라고들 한다. 

API의 공유, 테스트, 개발 등등을 도와주고 url요청시 응답결과 또한 알려줄 수 있는데

지금 사용하는 게 아마 응답결과를 받아오는 기능인 것 같다.

 

postman으로 확인한 url request 결과

 

 

 

 

 

 

 

 

 

4. 디자인

 

이왕 하는 프로젝트인 거 간단하지만 원래 페이지보단 예쁘게 꾸미고 싶어서 컬러파레트를 참조하고 디자인했다.

그리고 우리 학교 이름도 그대로 쓰긴 좀 그래서... 호그와트로 개명했다

 

 

 

참조한 컬러 파레트 사이트(Color Hunt) : https://colorhunt.co/ 

 

Color Palettes for Designers and Artists - Color Hunt

Discover the newest hand-picked color palettes of Color Hunt. Get color inspiration for your design and art projects.

colorhunt.co

 

 

 

 

 

 

 

 

5. 코드

 

 

<nav> 태그와 상단의 기숙사 소개를 하는 section을 제외하곤 JS에서 DOM태그를 연결해주는 방식으로 진행했다.

 

 

 

 

 

 

html

 

<!DOCTYPE html>
<html lang="ko">
<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">
    <link rel="stylesheet" href="/css/meal.css">
    <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=Josefin+Slab:ital,wght@1,200&family=Nanum+Gothic&family=Roboto:ital,wght@1,100&display=swap" rel="stylesheet"> 
    <title>학교기숙사 식단</title>
</head>
<body>
    <div id="container">
        <nav>
            <div id="nav_title">
                <h1>Hogwarts</h1>
            </div>
            <div id="login_button">
                <button>login</button>
            </div>
        </nav>

        <article id="domitary_meal">

            <!-- !헤더! -->
            <header id="banner">
                <div id="banner_center_container">
                    <div id="left_banner">
                        <div id="banner_title">
                            <h1>Hogwarts Domitary</h1>
                        </div>
                        <div id="banner_sub_title">
                            <p>Ravenclas & Hufflepuff</p>
                        </div>
                        <div id="banner_explain">
                            Too many cooks spoil the broth.<br>
                            Now, I am.
                        </div>
                    </div>
        
                    <div id="right_banner">
                        <img src="" alt="">
                    </div>
                </div>
            </header>
    
            <!-- !section 1 -->
            <section id="today_meal">
                <h1 class="section_titles">
                    <span class="orange_color">T</span>oday's <span class="orange_color">L</span>unch & <span class="orange_color">D</span>inner
                </h1>
    
                <div id="first_section_left_side">
                    <div id="print_today_meal">
                        <div id="today_lunch"> </div>
                        <div id="today_dinner"></div>
                    </div>
                </div>

                <div id="first_section_right_side">
                    <!-- !!여기 이미지 넣어줘야함 -->
                </div>
            </section>


            <!-- !section2 -->
            <section id="weekly_meal">
                <h1 class="section_titles">Weekly meal</h1>

                <!-- <div class="weekly_meal_container">
                    <div class="center_container">
                        <h1>2022-04-17</h1>
                        <p class="weekly_lunch"></p>
                        <p class="weekly_dinner"></p>
                    </div>
                </div> -->

                <!-- !이게 6개 있어야함 -->
            </section>
        </article>
    </div>
    <script type="module" src="/js/mainMeal.js"></script>
</body>
</html>

 

JS에서 DOM태그들을 연결해주었을 때 완성 모습을 미리 HTML에 주석처리 해놓는 게 꽤 편한 것 같다.

 

섹션을 잘 구분하기 위한 방법을 모색하다보니 html 태그에 대한 공부도 해야겠다는 걸 많이 느꼈다.

 

 

 

 

 

 

 

 

 

JS

 

 

JS를 import하고 export 하는 법을 써보고 싶어서 JS파일을 두개로 나누었다.

 

 

 

 

mainMeal.js - 받아온 데이터를 DOM태그로 연결해주는 JS

meal.js - fetch함수로 데이터를 받아오는 JS

 

 

mainMeal.js

import MealAPI from "./meal.js"


call_meal();

function call_meal() {
    const my_meal = new MealAPI();

    my_meal.mealAPI().then(res => {
        return res;
    }).then( data => {
        today_lunch_dinner(data);
        weekly_meal(data);
    })
    .catch( err => {
        console.log(err);
    })
}

function today_lunch_dinner(mealobj) {
    const lunch_text = document.querySelector('#today_lunch');
    const dinner_text = document.querySelector('#today_dinner');
    
    mealobj[0].mealNm.split('/').map( word => {
        const orange_span = document.createElement('span');
        const lunch_span = document.createElement('span');

        orange_span.className = 'orange_color';
        lunch_span.className = 'lunches dinners';

        lunch_span.innerHTML = word.slice(1);
        orange_span.innerHTML = word[0];

        lunch_span.prepend(orange_span);
        lunch_text.appendChild(lunch_span);
    });

    mealobj[1].mealNm.split('/').map( word => {
        const orange_span = document.createElement('span');
        const dinner_span = document.createElement('span');

        orange_span.className = 'orange_color';
        dinner_span.className = 'lunches dinners';

        dinner_span.innerHTML = word.slice(1);
        orange_span.innerHTML = word[0];

        dinner_span.prepend(orange_span);
        dinner_text.appendChild(dinner_span);
    });

}


function weekly_meal(mealobj) {
    const second_section = document.querySelector('#weekly_meal');

    for (let day=1; day <= 6; day++) {
        const weekly_meal_container = document.createElement('div');
        const center_container = document.createElement('div');
        const meal_date_h1 = document.createElement('h1');
        const lunch_p = document.createElement('p');
        const dinner_p = document.createElement('p');
        const meal_date = mealobj[day * 2].mealDate;
        const lunch = mealobj[day * 2];
        const dinner = mealobj[day*2 + 1];


        weekly_meal_container.className = 'weekly_meal_container';
        center_container.className = 'center_container';
        lunch_p.className = 'weekly_lunch';
        dinner_p.className = 'weekly_dinner';

        meal_date_h1.innerHTML = meal_date;
        lunch_p.innerHTML = lunch.mealNm;
        dinner_p.innerHTML = dinner.mealNm;

        second_section.appendChild(weekly_meal_container);
        weekly_meal_container.appendChild(center_container);
        center_container.appendChild(meal_date_h1);
        center_container.appendChild(lunch_p);
        center_container.appendChild(dinner_p);
    }
}

 

 

 

meal.js

export default class MealAPI {
    constructor() { // fetch 함수 object
        this.request_option = {
            method : 'GET',
            redirect : 'follow'
        };
    }

    meal_after_7day() { //날짜 계산
        const today = new Date();
        const today_date = today.getDate();
        const today_month = today.getMonth();
        const today_year = today.getFullYear();
        const endDt = new Date(today_year, today_month, today_date + 7);

        return endDt;
    }

    async mealAPI() { //json 데이터반환
        const endDt = this.meal_after_7day().toISOString().split('T')[0];
        const startDt = new Date().toISOString().split('T')[0];

        const response = await fetch(
            `https://api.pusan.ac.kr:8443/meal/sub?no=3&startDt=${startDt}&endDt=${endDt}`, 
            this.request_option
            ); //이렇게 쓰니까 확실히 가독성이 좋다
        const result = (await response).json();
        
        return result;
    }

}

 

 

 

mainMeal.js - call_meal()함수

function call_meal() {
    const my_meal = new MealAPI();

    my_meal.mealAPI().then(res => {
        return res;
    }).then( data => {
        today_lunch_dinner(data);
        weekly_meal(data);
    })
    .catch( err => {
        console.log(err);
    })
}

다른 js파일에 있는 MealAPI클래스의 mealAPI() 메소드를 이용해 식단 데이터를 불러온다.

아직 json 데이터를 처리하고 받아오는 데 많이 애를 먹는다.

첫번 째 reponse 객체를 반환하지 않고 바로 response객체의 요소들에 접근하려 해서 시간을 많이 썼다...

 

반환한 response 객체는 data라는 변수에 담기고, 바로 이게 json객체다.

json 객체를 오늘의 식단 & 이번주 식단을 표시해 주는 함수에 각각 매개변수로 주었다.

 

 

 

mainMeal.js - today_lunch_dinner(mealobj) 함수

function today_lunch_dinner(mealobj) {
    const lunch_text = document.querySelector('#today_lunch');
    const dinner_text = document.querySelector('#today_dinner');
    
    mealobj[0].mealNm.split('/').map( word => {
        const orange_span = document.createElement('span');
        const lunch_span = document.createElement('span');

        orange_span.className = 'orange_color';
        lunch_span.className = 'lunches dinners';

        lunch_span.innerHTML = word.slice(1);
        orange_span.innerHTML = word[0];

        lunch_span.prepend(orange_span);
        lunch_text.appendChild(lunch_span);
    });

    mealobj[1].mealNm.split('/').map( word => {
        const orange_span = document.createElement('span');
        const dinner_span = document.createElement('span');

        orange_span.className = 'orange_color';
        dinner_span.className = 'lunches dinners';

        dinner_span.innerHTML = word.slice(1);
        orange_span.innerHTML = word[0];

        dinner_span.prepend(orange_span);
        dinner_text.appendChild(dinner_span);
    });

}

뒤에 일주일 식단을 출력하는 함수를 작성하고 나서 해당 함수를 보니 더 간결하게 작성할 수 있지 않았을까 하는 아쉬움이 남는다.

json객체의 첫번째와 두번째 객체는 오늘 날짜의 식단이다. (중식과 석식)

 

식단을 처음 받아오면 아래처럼 슬래쉬(/)로 구분되어 있는데 이게 별로 안 예뻐서

첫번째 글자에만 오렌지 컬러로 포인트를 주고 싶었다.

 

 

 

 

 

처음엔 p태그 안에 담길 문자열들을 슬래시로 구분해서 첫번째 글자에만 span태그로 스타일을 주려했다.

그렇게 span을 준 문자열들을 다시 join()으로 합쳐서 표시하려고 했다.

 

그런데 내가...innerHTML 의 동작을 제대로 이해 못해서 계속 마지막 반찬만 화면에 표시됐다.

문자열로 합쳐버린 문자들에 태그들이 그대로 적용됐을 리도 없고... ㅋㅋㅋㅋ

 

실수했다는 걸 깨달아서 p 태그가 아니라 div 태그의 자식들로 각 반찬을 연결했다.

 

완료~~

 

 

 

 

 

mainMeal.js - weekly_meal(mealobj)함수

function weekly_meal(mealobj) {
    const second_section = document.querySelector('#weekly_meal');

    for (let day=1; day <= 6; day++) {
        const weekly_meal_container = document.createElement('div');
        const center_container = document.createElement('div');
        const meal_date_h1 = document.createElement('h1');
        const lunch_p = document.createElement('p');
        const dinner_p = document.createElement('p');
        const meal_date = mealobj[day * 2].mealDate;
        const lunch = mealobj[day * 2];
        const dinner = mealobj[day*2 + 1];


        weekly_meal_container.className = 'weekly_meal_container';
        center_container.className = 'center_container';
        lunch_p.className = 'weekly_lunch';
        dinner_p.className = 'weekly_dinner';

        meal_date_h1.innerHTML = meal_date;
        lunch_p.innerHTML = lunch.mealNm;
        dinner_p.innerHTML = dinner.mealNm;

        second_section.appendChild(weekly_meal_container);
        weekly_meal_container.appendChild(center_container);
        center_container.appendChild(meal_date_h1);
        center_container.appendChild(lunch_p);
        center_container.appendChild(dinner_p);
    }
}

 

해당 함수는 6일 후까지의 식단을 출력한다.

날짜별로 중식과 석식을 한 컨테이너 안에 묶고 싶었는데 처음엔 알고리즘을 잘못짜서 컨테이너가 이상하게 나뉘었다.

 

중식과 석식의 날짜가 같으니 중식일때마다 컨테이너 태그를 생성하는 식으로 반복문을 작성했는데... 반복문이 하나 돌고 나면 변수가 사라진다는 걸 또 깜빡해서 (ㅋㅋㅋㅋ..) 석식에겐 부모태그가 사라지는 사태가 발생했다...

 

그래서 아예 일수를 반복문으로 선언하고 거기에다 2를 곱해주는 식으로 중식과 석식을 처리했다.

 

 

 

 

 

 

 

meal.js - 생성자함수

    constructor() { // fetch 함수 object
        this.request_option = {
            method : 'GET',
            redirect : 'follow'
        };
    }

fetch 함수의 두번째 매개변수로 받아올 객체의 형식을 정할 수 있다.

http method로는 데이터롤 받아오므로 GET으로 설정해주고,

redirect를 허용할 것이기 때문에 follow로 설정했다.

 

 

 

 

mealAPI() 메소드 

    async mealAPI() { //json 데이터반환
        const endDt = this.meal_after_7day().toISOString().split('T')[0];
        const startDt = new Date().toISOString().split('T')[0];

        const response = await fetch(
            `https://api.pusan.ac.kr:8443/meal/sub?no=3&startDt=${startDt}&endDt=${endDt}`, 
            this.request_option
            ); //이렇게 쓰니까 확실히 가독성이 좋다
        const result = (await response).json();
        
        return result;
    }

 

MealAPI 클래스 내의 mealAPI() 메소드는 식단 데이터를 fetch함수로 받아와서 result로 반환한다.

url의 시작날짜와 끝 날짜를 YYYY-MM-DD 의 형식으로 변환해주어야 해서 날짜를 받아오는 함수에 형식변환 메소드를 취했다.

 

async와 await에 대해선 가독성이 떨어지는 익명함수 형태의 콜백 대신 써주는 비동기처리 구문이라고 알고 있고...

참고한 코드에서도 해당 문법을 사용해서 똑같이 써봤다(...)

어떻게 동작하는진 따로 공부해야겠다.

 

 

 

6. 그리하여 완성한 웹!

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

나름 디자인한다고는 했는데 아직까지 많이 미숙하고 좀 더럽다(...

호그와트 사진도 너무 번잡해 보여서 그냥 빼버렸다~

 

반응형도 생각해봤는데 더 본격적인 프로젝트할 때 하는 게 좋을 것 같아서 그냥 이 상태로 완성했다

그리고 그 사이 이것저것 이론이랑 git 공부한다고 시간도 훌쩍 지나가버리고... ㅋㅋㅋㅋ ㅠㅠ 

 

그래도 이번 프로젝트 덕에 CSS의  flex, 가상요소, background 를 많이 사용할 수 있었다.

JS에서 데이터를 받아 연결하는 알고리즘에 대한 고민도 해볼 수 있었고...

문제를 해결할 때마다 공부하고 알아가는 것들이 많아져서 즐거웠다. 

 

새로 익힌 CSS 속성에 대해선 이 다음에 다시 정리해봐야겠다. 

 

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함