본문 바로가기
STUDY/JavaScript

[Study] API를 활용하여 날씨 페이지 구성하기

by bottlesun 2022. 11. 26.
728x90

기능

  • https://openweathermap.org/api API 활용하여 날씨 페이지 구현
  • 버튼 클릭시 해당 지역 날씨 표시 기능 구현
  • 페이지네이션 기능 구현
  • 오류 발견 시 화면단에 오류 내용 출력
  • 날씨 온도에 따라 색 변경 기능 구현
  • 반응형 홈페이지 구현

사용언어

  • HTML
  • CSS
  • JavaScript

Demo App

API를 활용하여 날씨 페이지 구성하기

해당 API 페이지의 기본적인 날씨 데이터를 받아서 작업을 진행했다.
중심적으로 공부를 하려고 했던 목표는 axios로 API를 활용하는 부분이였다.

01. openweathermap.org/api 사용하기

https://openweathermap.org/current

해당 사이트에서 날씨 데이터를 받기위해 필요한건 회원가입후 생성하는 APIKEY , 원하는 위치의 자리의 좌표가 필요하다고 나온다.


해당 홈페이지는 친절하게도 좌표가 아닌 도시 이름 및 나라 코드 등으로도 검색을 할 수 있었고,
방대한 자료 속 에서 limit를 걸어 필요한 정보만 받을 수 있었다.

02. axios 란?

Ajax와 더불어 백엔드 프론트엔드와의 통신을 쉽게 하기 위에 사용하는 PromiseAPI를 활용하는
HTTP 비동기 통신 라이브러리이다.

fetch api 가 있지만, 굳이 axios 를 사용했던 이유는 , react vue 와 같은 프레임워크 에서
ajax를 구현할때 많이 사용 되기 때문에 바닐라 JS환경에서도 활용했다.

axios를 사용하려면, cdn이나 npm방식으로 파일을 불러와서 적용 시켜줘야한다.

//cdn 방식 (html파일에서)
 <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
//npm 방식 (터미널에서)
npm install axios

API 통신하기

API로 불러온 데이터가 여러 부분으로 계속해서 사용 되기 때문에,
axios에서 async/await를 사용할 수 있는 방법을 사용하여 데이터를 받아 왔다.

const getData = async () => {
  try {
    const response = await axios.get(`${URL}`);
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

03. 리스트 불러오기

해당 기능구현에서의 가장 고민이었던 부분이 도시를 어떤식으로 다 불러와야 할까였다.

대량의 전세계 정보가 들어있는 JSON 파일

http://bulk.openweathermap.org/sample/

대량의 리스트에서 map핑을 통해 data 정보를 확인해봤더니

너무 너무 너무 방대한 정보들이 딸려오기에 필요한 정보만 추출하기 위해서
if문으로 노가다를 돌려, 정보를 받아왔다.

        let data2 = response2.data;
        data2.map((i)=>{
            if(i.country == 'KR'){
                console.log(i)
            }
        })

country 정보에서 KR로 된 API 데이터들을 if문으로 걸러서 추출을 했다.

04. 날짜 불러오기 (render)

받아온 데이터를 HTML 화면에 출력을 해주기 위해 render 라는 함수를 만들어
화면으로 보여질 부분들에 대한 부분을 다 넣어줬다.

const render = () => {
    try {
        let list = FilterList;
        let createHTML = ""; 
        createHTML = list.slice(((page-1) * limit), ((page-1) * limit) + limit).map((list, i) => {
            let description = list.weather[0].description;
            return `<article class="weather_item rounded drop-shadow overflow-hidden
            ${((list.main.temp - 273.15).toFixed(1) >= 20) ? "hot" : ((list.main.temp - 273.15).toFixed(1) <= 5) ? "cool" : 'soso'}">
        <div class="main_info flex" >
            <div class="weather_icon"><i class="fa-solid "></i></div>
            <div class="weather_info flex gap-2">
                <div class="flex centers gap-2"><i class="fa-solid fa-temperature-half"></i> <span>${(list.main.temp - 273.15).toFixed(1)}℃</span></div>
                <p>${description}</p>
                <p class="weatherCity"> ${list.name} , ${list.sys.country == "KR" ? "한국" : list.sys.country}</p>
            </div>
        </div>
        <ul class="sub_info centers flex mx-auto p-5 bg-white">
            <li><i class="fa-solid fa-temperature-arrow-up"><span>${(list.main.temp_max - 273.15).toFixed(1)}℃</span></i></li>
            <li><i class="fa-solid fa-temperature-arrow-down"><span>${(list.main.temp_min - 273.15).toFixed(1)}℃</span></i></li>
        </ul>
    </article>
    `
        }).join('');
        document.querySelector('.weather').innerHTML = createHTML;
        changeWeatherIcon();
    } catch (error) {
        console.log(error.message);
        errorRender(error.message)
    }
}

05.날씨 아이콘 변경

api 자체에서도 icon이 있었지만 해당 icon들이 맘에 들지 않아서
fontawesome에서 아이콘을 가지고 와 사용하였다.
날씨들 정보에 따라서, 아이콘이 바뀌어야 하는데, fontawesome은 class로 아이콘들이 바뀌기때문에 if문으로 description 데이터 값에 따라서 class값을 바꿔주었다.

 

/* 날씨 아이콘 변경 */
const changeWeatherIcon = () => {
    let list = FilterList;
    let weather_icon = document.querySelectorAll('.weather_icon i');
    weather_icon.forEach((icon, v) => {
        for (let i = 0; i < list[v].weather.length; i++) {
            let description = list[v].weather[i].description;
            if (description == 'clear sky') {
                icon.classList.add('fa-sun');
            } else if (description == 'few clouds') {
                icon.classList.add('fa-cloud-sun');
            } else if (description.includes('clouds') || !(description == 'few clouds')) {
                icon.classList.add('fa-cloud');
            } else if (description.includes('rain')) {
                icon.classList.add('fa-cloud-rain');
            } else if (description == 'thunderstorm') {
                icon.classList.add('fa-cloud-bolt');
            } else if (description == 'snow') {
                icon.classList.add('fa-snowflake');
            } else if (description == 'mist') {
                icon.classList.add('fa-water');
            }
        }
    });
}

06. 버튼 클릭에 따라 날짜 나타나기

버튼 클릭에 따라 해당 지역의 현재온도를 가지고와 출력해줬다.
온도에 따라 글씨의 색상을 바꿔주어 더운지 추운지 괜찮은지를 표시해주었고,
API에서 받아오는 온도 정보는 화씨온도이기에 (화씨온도 - 273.15).toFixed(1) 를 하여 섭씨 온도로 변환해 출력해줘야 한다.

 

/* 버튼 */
const menuButton = async (event) => {
    let CityName = CityArr;
    let thisButton = event.target;
    let ThisTemp =  FilterList.map((v,i) => {
     return thisButton.innerText == CityName[i].name ?  (v.main.temp - 273.15).toFixed(1)  : ""
    }).join('');  
    document.querySelector('.weather_text').innerHTML =
    ` 오늘 ${thisButton.innerText}의 온도는?
    <span class="font-bold ${ThisTemp >= 20 ? "text-red-400" :  ThisTemp <= 5 ? "text-blue-700" : 'text-green-600' }">${ThisTemp}</span>
    ℃ 입니다. `
} 

07. 페이지네이션 구현하기

JS로 페이지네이션 구현하려고 할때, 사용되는 공식이 있다.

totalPage = Math.ceil(데이터 전체 갯수 / 화면에 보일 페이지 갯수)
pageGroup = Math.ceil(현재페이지 / 화면에 보일 페이지 갯수)
last = pageGroup * 화면에 보일 페이지 갯수
first = last - (화면에 보일 페이지 갯수 -1)

로 값을 구할 수 있다.

/* pagelation */
const pagelation = () => {
    let pageNationHTML = "";
    let totalPage = Math.ceil(totalCount / pageCount) // 총 페이지네이션 / 한 페이지에 보여줄 글의 최대 갯수
    let pageGroup = Math.ceil(page / pageCount) // 현재 페이지 / 보여질 페이지네이션 수
    let last = pageGroup * pageCount; // 마지막 페이지
    if (last > totalPage) {
        // 마지막 그룹이 5개 이하이면
        last = totalPage;
    }
    let first = last - (pageCount - 1);  // 첫번째 페이지
    pageNationHTML = page == 1 ? "" : `<li class=" bg-indigo-500 shadow-lg py-1 px-4  py-2 rounded hover:bg-white hover:text-indigo-500" onClick="moveTo(${page-1})">&lt</li>`
    for (let i = first; i <= last; i++) {
        pageNationHTML += `
    <li class="${page == i ? 'active' : ""} bg-indigo-500 shadow-lg py-1 px-4 -2 py-2 rounded hover:bg-white hover:text-indigo-500" onClick="moveTo(${i})">${i}</li>
    `
    }
    pageNationHTML += page == totalPage ? "" : page >= 1 ? `<li class=" bg-indigo-500 shadow-lg py-1 px-4 py-2 rounded hover:bg-white hover:text-indigo-500" onClick="moveTo(${page+1})">&gt</li>` : ""
    document.querySelector('.pagination').innerHTML = pageNationHTML;
}

07-1. 페이지네이션 구현에 대한 문제점

페이지네이션 구현을 할때 시간이 가장 오래 걸렸는데, 그 이유는
페이지네이션은 작동하지만 화면이 페이지 별로 변경되지 않았다.
받아오던 데이터를 render 화면에서 map으로 보여줄때에도 10개면 10개 5개면 5개를 전체적으로 데이터를 다 읽어오기때문에, 결국 화면에 출력이 되는건 끝에서 보여지게 했던 3개 뿐이였다.

그래서 이 부분을 해결하기 위해서

list.slice(((page-1) * limit), ((page-1) * limit) + limit).map((list) => {

map을 사용할때, 동적으로 현재 페이지 에서 부터 한번에 보여질 데이터의 값 만큼만 map으로 출력을 하게 되면 현재 페이지의 숫자 값에 따라 다른 인덱스 번호의 정보를 출력해주기때문에,
동적으로 페이지네이션 값에 따라 정보가 변하도록 만들 수 있었다.

728x90

'STUDY > JavaScript' 카테고리의 다른 글

[JavaScript] 상수(const)  (0) 2022.11.27
[JavaScript] 변수(let , var)  (0) 2022.11.27
[JavaScript] JS 사용하기  (0) 2022.11.27
[JavaScript] JS 알아보기  (0) 2022.11.27
[Study] API를 활용하여 뉴스페이지 구성하기  (0) 2022.11.26

댓글