카테고리 없음

[Vue.js] 날씨 웹앱 만들기

nh_3521099031483 2024. 4. 4. 14:17

기상청 API를 이용한 날씨 웹앱 만들기

 

 

단기예보 데이터를 이용해서 시간대별 날씨정보 구현하기

 

데이터 형식

시간대별로 나누어 진게 아닌 카테고리별로 나누어져 있다.

모든 카테고리의 항목들이 필요하지는 않기 때문에 원하는 카테고리만 추출할 것이다

getters: { // arrayTemps가 원본데이터이다
    filteredTempData(state) { // 기온
      return state.arrayTemps.filter(temp => temp.category === 'TMP')
    },
    filteredPopData(state) { // 강수량
      return state.arrayTemps.filter(temp => temp.category === 'POP')
    },
    filteredSkyData(state) { // 하늘상태
      return state.arrayTemps.filter(temp => temp.category === 'SKY')
    }
  },

mapgetter 메서드를 이용해서 데이터를 vue파일의 computed메서드 안으로 불러와 준다.

...mapGetters('weatherApi', [
      'filteredTempData',
      'filteredPopData',
      'filteredSkyData',
    ]),

 

현재 습도 풍속 강수확률을 나타내주기 위해서 해당 데이터들을 추출한다.

// state안에 선언
temporaryData: [ 
        {
          title: '습도',
          value: '',
        },
        {
          title: '풍속',
          value: '',
        },
        {
          title: '강수확률',
          value: '',
        },
      ],
// mutation안에 선언
 
SET_WEATHER_DATA(state, data) {
      state.temporaryData[0].value = data.item[10].fcstValue + "%"; // 습도
      state.temporaryData[1].value = data.item[4].fcstValue + "m/s"; // 풍속
      state.temporaryData[2].value = data.item[7].fcstValue + "%"; // 강수확률
}

 

렌더링 될 vue 파일에 불러와 준다

computed: {
    ...mapState('weatherApi', [
      'temporaryData',
    ]),
   
  },

 

v-for 바인딩을 사용하여 렌더링

<div class="weatherData">
                  <div v-for="temporary in temporaryData" :key="temporary.title" class="detailData">
                      <p>{{ temporary.title }}</p>
                      <p>{{ temporary.value }}</p>
                  </div>
              </div>

 

시간대별 날씨정보 바인딩

 

시간대에 맞는 강수량을 찾는 함수

methods: {
    getPopValue(fcstTime) {
      const popData = this.filteredPopData.find(data => data.fcstTime === fcstTime)
      return popData ? popData.fcstValue : '-'
    },
  },

 

filteredTempData의 fcstTime(시간) 과 같은 시간의 강수량 데이터를 찾으면 되는 것이다. 

<div class="timelyWeather" v-for="(temp, index) in filteredTempData" :key="index">
                  <div class="icon">
                    <img :src="images[index]" alt="hour" />
                  </div>
                  <div class="data">
                      <p class="time">
                        {{ temp.fcstTime.slice(0, 2) }}시
                      </p>
                      <p class="currentDegree">{{ temp.fcstValue }}&deg;</p>
                      <div>
                          <img src="src/assets/images/drop.png" alt="빗방울" />
                          <p class="fall">{{ getPopValue(temp.fcstTime) }}%</p>
                      </div>
                  </div>
              </div>

 

이미지 처리

 

이미지 경로를 동적으로 처리한다. 배포할 것이 아니기 때문에 로컬로 접근한다.

const images = state.arrayTemps.filter(temp => temp.category === 'SKY').reduce((acc, cur) => { // 함수를 사용하여 하늘 상태 데이터만 추출
          // reduce 함수를 사용하여 추출된 데이터를 순회하며 이미지 경로 배열을 생성
          const weatherIconValue = parseInt(cur.fcstValue); // 문자열을 정수형으로 변환
          // console.log(typeof weatherIconValue)
          const iconPath = (() => {
            switch (weatherIconValue) {
              case 1:
                return 'src/assets/images/sunny.png';
              case 2:
                return 'src/assets/images/02d.png';
              case 3:
                return 'src/assets/images/03d.png';
              case 4:
                return 'src/assets/images/04d.png';
              default:
                return 'src/assets/images/sunny.png';
            }
          })();
          acc.push(iconPath);
          return acc;
        }, []);
       
       
        commit('SET_IMAGEPATH', images);

 

렌더링할 vue파일의 computed메서드 안에 store데이터를 사용하기 위해 선언해준다

images() {
      return this.$store.state.weatherApi.images;
    },

 

첫번째 이미지 데이터가 현재 하늘 상태의 이미지를 보여준다.

<div class="weatherIcon">
                  <img :src="images[0]" alt="MainLogo" />
              </div>

 

filteredTempData의 갯수와 filteredSkyData의 갯수가 같이 때문에 images[index]로 v-for 바인딩 해준다

<div class="timelyWeather" v-for="(temp, index) in filteredTempData" :key="index">
                  <div class="icon">
                    <img :src="images[index]" alt="hour" />
                  </div>
....