오늘은 날씨 오픈 API를 활용해서 간단하게 만들어보았다! 단점은... 영어로만 도시를 검색해야한다는 점 ㅜㅜ
되게 간단한 기능인데도 자스 코드가 그렇게 간결하지가 않다.. (최대한 리팩토링 해봤는데도..)
아마 괜히 효과주고 싶어서 gsap랑 css 뭐 이것저것 넣었는데 별 호과없음 ㅋㅋㅋ
다음엔 좀 더 멋지게 만들어야징.
Weather App
구조
<div class="star">
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
<div class="shooting_star"></div>
</div>
<!-- // 배경 -->
<!-- 날씨 -->
<div class="card">
<!-- 서치 -->
<div class="search">
<input type="text" placeholder="Enter City Name!" spellcheck="false" />
<button><img src="images/search.png" alt="search" /></button>
</div>
<!-- 에러 문구 -->
<div class="error">
<p>유효하지 않습니다! 다시 한 번 확인해주세요.</p>
</div>
<!-- // 서치 -->
<!-- 날씨 -->
<div class="weather">
<img src="" class="weather-icon" />
<h1 class="temp"></h1>
<p class="status"></h2>
<h2 class="city"></h2>
<div class="details">
<div class="col">
<img src="images/humidity.png" alt="humidity" />
<div>
<p class="humidity"></p>
<p>습도</p>
</div>
</div>
<div class="col">
<img src="images/wind.png" alt="wind" />
<div>
<p class="wind"></p>
<p>풍속</p>
</div>
</div>
</div>
</div>
<!-- // 날씨 -->
</div>
<!-- //날씨 -->
배경쪽은 무시해주시고 ㅎㅎ..
에러문구는 display: none으로 감춰놨다가 if문을 사용해 잘못 검색했을 시 에러 문구를 노출시키게끔 스크립트를 짰다.
CSS
@font-face {
font-family: "SUIT-Regular";
src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_suit@1.0/SUIT-Regular.woff2")
format("woff2");
font-weight: normal;
font-style: normal;
}
* {
margin: 0;
padding: 0;
font-family: "SUIT-Regular";
box-sizing: border-box;
}
.card {
position: relative;
z-index: 1000;
width: 90%;
max-width: 470px;
background: rgb(40, 158, 80);
background: linear-gradient(
0deg,
rgba(40, 158, 80, 1) 0%,
rgba(90, 143, 244, 1) 100%
);
color: #fff;
margin: 100px auto 0;
border-radius: 20px;
padding: 40px 35px;
text-align: center;
}
.search {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.search input {
border: 0;
outline: 0;
background-color: #ebfffc;
color: #555;
padding: 10px 25px;
height: 60px;
border-radius: 30px;
flex: 1;
margin-right: 16px;
font-size: 18px;
}
.search button {
border: 0;
outline: 0;
background-color: #ebfffc;
border-radius: 50%;
height: 60px;
width: 60px;
cursor: pointer;
}
.search button img {
width: 16px;
}
.weather-icon {
width: 170px;
margin-top: 30px;
}
.weather h1 {
font-size: 80px;
font-weight: 500;
}
.weather p {
font-size: 20px;
}
.weather h2 {
font-size: 45px;
font-weight: 400;
}
.details {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
margin-top: 50px;
}
.col {
display: flex;
align-items: center;
text-align: left;
}
.col img {
width: 40px;
margin-right: 10px;
}
.humidity,
.wind {
font-size: 28px;
margin-top: -6px;
}
.error {
margin-top: 20px;
margin-left: 10px;
text-align: left;
font-size: 15px;
display: none;
}
배경 부분 css는 따로 분리해서 star.css라는 파일에 스타일링 했습니당. 궁금하신 분들은 글 마지막에 깃헙 주소를 참고!!!
스크립트
const apiKey = "0d1035fe5af6b099a1a42c5023236bd7";
const apiUrl =
"https://api.openweathermap.org/data/2.5/weather?units=metric&q=";
const weatherCard = document.querySelector(".weather");
const error = document.querySelector(".error");
const searchBox = document.querySelector(".search input");
const searchBtn = document.querySelector(".search button");
const weatherIcon = document.querySelector(".weather-icon");
const weatherIconMapping = {
Clouds: "clouds",
Clear: "clear",
Rain: "rain",
Drizzle: "drizzle",
Mist: "mist",
Snow: "snow",
Wind: "wind",
};
async function checkWeather(city) {
const response = await fetch(apiUrl + city + `&appid=${apiKey}`);
if (response.status == 404) {
// Show error message
weatherCard.style.display = "none";
error.style.display = "block";
} else {
// Reset error display
error.style.display = "none";
const data = await response.json();
const weatherId = data.weather[0].id;
const koreanDescription = weatherDescKo.find((entry) => entry[weatherId]);
document.querySelector(".city").innerHTML = data.name;
document.querySelector(".status").innerHTML = data.weather[0].id;
document.querySelector(".temp").innerHTML =
Math.round(data.main.temp) + "°C";
document.querySelector(".humidity").innerHTML = data.main.humidity + "%";
document.querySelector(".wind").innerHTML = data.wind.speed + "km/h";
if (koreanDescription) {
const description = koreanDescription[weatherId];
document.querySelector(".status").innerHTML = description;
} else {
document.querySelector(".status").innerHTML = "Unknown Weather";
}
if (data.weather[0].main in weatherIconMapping) {
weatherIcon.src = `images/${
weatherIconMapping[data.weather[0].main]
}.png`;
}
// Show weather card
weatherCard.style.display = "block";
}
}
// 초기에는 max-height를 0으로 설정
weatherCard.style.maxHeight = 0;
weatherCard.style.overflow = "hidden";
// 엔터
searchBox.addEventListener("keypress", function (event) {
if (event.key === "Enter") {
checkWeather(searchBox.value);
gsap.to(weatherCard, {
maxHeight: "100vh",
duration: 1,
ease: "power2.inOut",
});
}
});
// 버튼
searchBtn.addEventListener("click", () => {
checkWeather(searchBox.value);
gsap.to(weatherCard, {
maxHeight: "100vh",
duration: 1,
ease: "power2.inOut",
});
});
뭔가 되게 쓸데없이 긴 거 같은 ㅋㅋㅋ
사실 api키도 .env로 분리하려했으나 너무나 간단한 기능이기에 그냥 스크립트에 적었습니다
1. API 키 및 URL
2. DOM 요소 참조
document.querySelector를 사용하여 다양한 HTML 요소에 대한 참조를 저장합니다. 이러한 요소들은 아마도 웹 페이지의 일부이며 날씨 정보를 표시하는 데 사용됩니다.
3. 날씨 아이콘 매핑(이미지)
이 매핑은 나중에 날씨 아이콘 이미지의 소스를 설정하는 데 사용됩니다.
4. checkWeather 함수
city를 매개변수로 받아서 해당 도시의 날씨 정보를 확인합니다.
API를 통해 데이터를 가져온 후, 404 에러인지 확인하여 에러 메시지를 표시하거나 날씨 정보를 업데이트합니다.
한글 날씨 설명이 있는 경우 해당 설명을 표시하고, 없는 경우 "Unknown Weather"를 표시합니다.(예외처리)
날씨 아이콘도 업데이트하고, 날씨 카드를 화면에 표시합니다.
5. 초기 상태 설정(GSAP)
웹 페이지가 로드될 때, 날씨 카드는 숨겨진 상태로 초기화됩니다.
6. 이벤트 리스너
검색 박스에서 엔터 키를 누르면 checkWeather 함수를 호출하고, 날씨 카드를 나타내는 애니메이션을 추가합니다.
검색 버튼을 클릭하면 동일하게 checkWeather 함수를 호출하고, 날씨 카드를 나타내는 애니메이션을 추가합니다.
이 부분은 날씨API의 response를 보면 id를 받아오는 것을 확인할 수 있는데, 구글링을 해보니 그 id를 다른 사람들이 친절하게 한글로 번역해 매핑을 다 해주셨다.. !!!
const weatherId = data.weather[0].id;
const koreanDescription = weatherDescKo.find((entry) => entry[weatherId]);
이런식으로 !!
그래서 index.html에 따로 매핑된 js파일을 연동해서 쓰면
id에 따라 한글이 출력되는 걸 볼 수 있다.
완성된 화면과 코드 보기
https://github.com/YeoDaSeul4355/web2023/tree/main/javascirpt/project/weather