전일에 이렇게 요청을 보내와서 사용 할 수 있게 파싱해왔으니
이제 파싱해온 데이터를 가지고 동적으로 컴포넌트들을 구성하자
WeatherRender
생성자 만들기class WeatherRender extends LocateFetch {
constructor(api) {
super(api);
this.setParams();
this.init();
this.cards = document.querySelectorAll('.card');
this.currentDate = new Date();
this.weatherData = undefined;
this.monthMap = {
0: 'january',
1: 'february',
2: 'march',
3: 'april',
4: 'may',
5: 'june',
6: 'july',
7: 'august',
8: 'september',
9: 'october',
10: 'november',
11: 'december',
};
this.dayMap = {
0: 'Monday',
1: 'Tuesday',
2: 'Wednesday',
3: 'Thursday',
4: 'Friday',
5: 'Saturday',
6: 'Sunday',
};
this.PTYmap = {
0: ['sunny', 'images/sunny.png'], // 맑음
1: ['rainy', 'images/rainy.png'], // 비
2: ['snow', 'images/snow.png'], // 비/눈
3: ['snow', 'images/snow.png'], // 눈
4: ['shower', 'images/rain-thunder.png'], // 소나기
5: ['windy', 'images/windy.png'], // 바람 많음
};
this.SKYmap = {
0: ['sunny', '/images/sunny.png'],
3: ['cloudy', '/images/cloudy.png'],
4: ['windy', '/images/windy.png'],
};
this.hours = Array.from({ length: 25 }, (_, i) => {
const paddedHour = `0${i}`.slice(-2);
return `${paddedHour}00`; // [0100 , 0200 ... 2400]
});
}
API
를 활용해 자료를 가져온 후 렌더링 해야 하기에
이전에 정보를 가져오는 WeatherFetch
를 상속받은 WeatherRender
생성자를 만들어주었다.
부모 생성자인 WeatherRender
의 파라미터를 setParamse() , init()
메소드를 실행시켜주고
파싱해온 자료들을 렌더링 하기 위해 객체들을 준비해주었다.
API
요청하고 적절한 이미지 배너 준비하기...
async getWeathers() {
// GET 요청을 보내지 않았을 때는 GET 요청을 받아오고
// 받아온적 있을 경우엔 이미 받아온 것을 return
if (!this.weatherData) {
this.weatherData = await this.parseResponse();
return this.weatherData;
}
return this.weatherData;
}
...
getWeathers
메소드는 parseResponse
이 한 번도 실행되지 않았다면 파싱해온 후 프로퍼티로 저장 후 반환하며
한 번이라도 실행되어 저장되어 있다면, 저장된 파싱 정보들을 반환하도록 하였다.
나름 싱글톤 패턴을 흘깃 하고 보긴했어서 비슷한 원리로 따라해봤다.
맞는지는 모르겠다. 지피티한테 이 악물고 "그래 나도 싱글톤 아닌건 알아, 그래도 비슷한 원리지 ?!" 이러고 물어봐도 계속 부정한다.
choiceSrc(ptyCode, skyCode) {
if (!ptyCode) {
return this.SKYMAP[skyCode];
}
return this.PTYmap[ptyCode];
}
파싱해온 정보들 중 PTY , SKY
라는 값들이 존재한다.
해당 값들은 PTY : 비가 온다면 어떤 상태, SKY : 하늘 상태
를 의미한다.
this.PTYmap = {
0: ['sunny', 'images/sunny.png'], // 맑음
1: ['rainy', 'images/rainy.png'], // 비
2: ['snow', 'images/snow.png'], // 비/눈
3: ['snow', 'images/snow.png'], // 눈
4: ['shower', 'images/rain-thunder.png'], // 소나기
5: ['windy', 'images/windy.png'], // 바람 많음
};
this.SKYmap = {
0: ['sunny', '/images/sunny.png'],
3: ['cloudy', '/images/cloudy.png'],
4: ['windy', '/images/windy.png'],
};
그렇기에 비가 오지 않는다면 SKYmap
에서 제목과 이미지 주소를 가져오고
비가 온다면 (혹은 눈) PTYmap
에서 제목과 이미지 주소를 가져오도록 하였다.
...
getDate() {
const { monthMap, dayMap } = this;
let hour = this.currentDate.getHours();
const index = `0${hour}`.slice(-2) + '00';
const meridie = hour >= 12 ? 'PM' : 'AM';
hour = hour >= 12 ? hour - 12 : hour;
const day = dayMap[this.currentDate.getDay()];
const date = this.currentDate.getDate();
const month = monthMap[this.currentDate.getMonth()];
return [hour, index, meridie, day, date, month];
}
...
카드배너에서 날짜와 시간등을 가져오기 위한 메소드를 만들어주었다.
여기서 index
에 해당하는 것은 파싱해온 데이터의 생김새가
다음처럼 생겼기 때문에 시간을 시간00
형태로 변경해주었다.
...
async renderMain(address) {
const [hour, index, meridie, day, date, month] = this.getDate();
const targetWeather = await this.getWeathers();
const { POP, PTY, REH, SKY, TMP, WSD } = targetWeather[address][index];
const [weatherState, src] = this.choiceSrc(PTY, SKY);
return `<div class="weather-wrapper">
<div class="main-weather">
<div class="header-weather">🌍${address}</div>
<div class="body-weather">
<img class="weather-img" src=${src} />
<div class="weather-text">
<div class="temperature-text">${TMP}℃</div>
<div class="state-text">${weatherState}</div>
<div class="date-text">
<span class="hour">${hour}</span>
<span span="meridie">${meridie}</span>,${day},${date}, ${month}
</div>
</div>
<hr class = 'cross-line' / >
<div class="weather-sub">
<div class="sub-wrapper">
<div class="weather-icon">💨</div>
<div class="datail-number">${WSD} km/h</div>
<div class="datail-text">wind</div>
</div>
<div class="sub-wrapper">
<div class="weather-icon">💧</div>
<div class="datail-number">${REH}%</div>
<div class="datail-text">Humidity</div>
</div>
<div class="sub-wrapper">
<div class="weather-icon">☂️</div>
<div class="datail-number">${POP}%</div>
<div class="datail-text">chance of <br />rain</div>
</div>
</div>
</div>
<div class="tail-weather"></div>
</div>`;
}
...
이전에 디자인 해놨던 컴포넌트를 반환값으로 가지고 온후
메인 페이지에 들어갈 파라미터들을 넣어주었다.
async renderMain(address) {
const [hour, index, meridie, day, date, month] = this.getDate();
const targetWeather = await this.getWeathers();
const { POP, PTY, REH, SKY, TMP, WSD } = targetWeather[address][index];
...
renderMain
함수는 지역 별 address
를 인수로 받아
해당 address
의 현재 시간에 따른 정보를 가져올 것이기 때문에 address
로 지역을 특정하고 index
로 시간을 특정하였다.
이후 반환되는 값들은 이전에 컴포넌트화해놨던 태그들을 담아주었다.
...
async renderAll() {
const { locateArr } = this;
const weatherData = await this.getWeathers();
locateArr.forEach((locate, index) => {
const { address } = locate;
const card = this.cards[index];
this.renderMain(address).then((res) => {
card.innerHTML = res;
});
});
}
}
...
이후 renderAll
에서는 locateArr
에 들어있는 지역을 순서대로 하여 메인 페이지를 렌더링 해주었다.
정보를 제공하는 홈페이지의 서버 환경에 따라 응답 받아오는 시간이 5000ms
까지 느려져 렌더링 되는데 5000ms
가 걸리기도 한다.
이를 해결하기 위해서는 서버 단에서 미리 정보들을 받아온 후 해당 서버에서
빠르게 가져오면 될 것 같다.
express
를 이용해서 서버를 파놓을까 하다가 깃허브 페이지를 만들기 위해서
그냥 그 부분은 포기하기로 했다.
저번에 했던
toDoList
를 서버를 만들어 깃허브에 올려놨드니
깃허브 페이지에서는 서버를 개인이 작동 시킬 수 없어 하루종일 만든게 실행이 안되더라토이프로젝트 이후 있을 프로젝트들에서는 백엔드 단과 함꼐 할 것이니 그 부분은 기대가 된다 룰루루
쌈뽕해보이는 고화질 사진을 배경으로 넣어주고 완성했다.
밑 서브 영역도 만들려면 만들 수 있었지만 디자인 하면서 만드는 방법은 이미 체득했기 때문에
이제는 다른 공부들 마저 하고 다음 스텝으로 넘어가야 겠다 생각했다. 그렇게 해야 사람들과 하는 프로젝트를 할 수 있을 것 같기 때문이다.
그래도 자주 이렇게 바닐라 자바스크립트로 토이프로젝트들은 계속 해야겠다.
하면서 배우는게 많았다. 이번에는 Promise.all
에 대한 개념을 한 번 더 확립 할 수 있었다.
조금 아쉬웠던 점은 반응형 웹스럽게 단위들도 바꿔볼 걸 하는 후회가 든다.
단위를 모두 px
단위로 하다보니 내 모니터에서는 잘 보이는 것들이
화면 크기를 축소하거나 확대하면 부자연스럽다.
다음번엔 단위를 염두해서 잘 만들어봐야겠다.