Vueでaxiosを使いAPIから天気情報を取得する方法

Vueを使ってopanweatherMap APIから天気情報を取得したのでメモします:raised_hand:

<h3>最終的に作ったもの</h3>
![spa api.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534681/4e13d89b-668a-0ba2-97f0-3c98b13bfe48.png)

<h3>環境</h3>
```package.json
"dependencies": {
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-axios": "^2.1.5"
  },
  "devDependencies": {
    "@fortawesome/fontawesome-free": "^5.14.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "axios": "^0.19",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "jquery": "^3.2",
    "node-sass": "^4.14.1",
    "sass": "^1.15.2",
    "vue-template-compiler": "^2.6.11"
  },

```  
<h3>テキストエディタ</h3>
phpstorm

<h3>ディレクトリ構成</h3>
src-component-Wather.vue
　　-App.vue
　　-main.js

<p>App.vueとmain.jsは特に変わったことはしておらず、コンポーネントを呼び出してるだけです。</p>
```vue:App.vue
<template>
  <div id="app">
    <Weather></Weather>
  </div>
</template>
<script>
  import Weather from "@/components/Weather";
  export default {
    components:{
      Weather
    },
  }
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

```
```js:main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false


new Vue({
  render: h => h(App),
}).$mount('#app')

```

<p>さて本題のWeater.vueです。
（順番に解説していきます）</p>
```vue:Weather.vue
<template>
  <div class="weather-position">
    <h3>直近５日間の３時間毎天気予報</h3>
    <p>GoogleMapから地図の緯度と経度をコピー&ペーストしてください<br>
    凡例：千葉県松戸市緯度35.770874,経度139.896050</p>
    <div class="lat-lon-position">
      <label for="lat" >緯度</label>
          <input id="lat" type="text" v-model="lat">
      <label for="lon" >経度</label>
          <input id="lon" type="text" v-model="lon">
    </div>
    <p v-if="lat && lon">
      <button @click="weatherPoint()" class="weather-get-button">天気情報取得</button>
    </p>
    <p class="weather_city">{{ city }}</p>
    <div v-for="post in posts" :key="post.dt">
      <div class="weather_item">
      {{post.dt|calc}}<br>
      {{post.main.temp}}℃<br>
      {{post.weather[0].main}}<br>
        <p v-if="post.weather[0].main === 'Rain'"><i class="fas fa-umbrella fa-3x"></i></p>
        <p v-else-if="post.weather[0].main === 'Clouds'"><i class="fas fa-cloud fa-3x"></i></p>
        <p v-else-if="post.weather[0].main === 'Clear'"><i class="fas fa-sun fa-3x"></i></p>
        <p v-else>該当しなかった<i class="fas fa-cloud-sun fa-3x"></i></p>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  data() {
    return {
      city: null, //地域名
      posts:[],//listのデータ一括取得
      baseurl : 'https://api.openweathermap.org/data/2.5/forecast?',
      lat:"",//入力値から取得
      lon:"",//入力値から取得
      units : '&units=metric&',//温度を摂氏で取得
      id : 'appid=キーが入ります',
    }
  },
  methods: {
    weatherPoint:function(){
      let url =this.baseurl + 'lat=' + this.lat + '&lon=' + this.lon + this.units + this.id;
      axios.get(url)
          .then(function (response) {
            this.city = response.data.city.name
            this.posts = response.data.list
          }.bind(this))
          .catch(function (error) {
            console.log(error)
          })
      }
    },
  filters: {
    calc(value) {
      let dateTime = new Date((value) *1000);
      return dateTime.toLocaleString("ja");
    }
  }//filters
}//export default
</script>

<style scoped>
.weather_item{
  text-align: left;
  border: 1px solid #2c3e50;
  display: inline-block;
  float:left;
  width:25%;
  height:180px;
  box-sizing: border-box;
}
p{
  margin:0;
}
.weather-position{
  background-image: url("../../src/assets/japan.png");
  border-radius: 8px;
  padding:20px 20px;
  overflow: hidden;
  -moz-border-radius: 8px;
  -webkit-border-radius: 8px;
}
.weather-get-button{
  position: relative;
  display: inline-block;
  padding:0.25em 0.5em;
  text-decoration: none;
  color:#fff;
  background: #fd9535;
  border-radius: 4px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
  box-shadow: inset 0 2px 0 rgba(255,255,255,0.2),inset 0 -2px 0 rgba(0,0,0,0.05);
  -moz-box-shadow: inset 0 2px 0 rgba(255,255,255,0.2),inset 0 -2px 0 rgba(0,0,0,0.05);
  -webkit-box-shadow: inset 0 2px 0 rgba(255,255,255,0.2),inset 0 -2px 0 rgba(0,0,0,0.05);
  font-weight:bold;
  border: solid 2px #d27d00;
}
.weather-get-button:active{
  box-shadow: 0 0 2px rgba(0,0,0,0.30);
  -moz-box-shadow: 0 0 2px rgba(0,0,0,0.30);
  -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.30);
}
.lat-lon-position{
  margin:30px;
}
</style>
```
<h3>テンプレートの中の解説</h3>
```
    <div class="lat-lon-position">
      <label for="lat" >緯度</label>
          <input id="lat" type="text" v-model="lat">
      <label for="lon" >経度</label>
          <input id="lon" type="text" v-model="lon">
    </div>
    <p v-if="lat && lon">
      <button @click="weatherPoint()" class="weather-get-button">天気情報取得</button>

```
<p>テキストに入力した値をv-modelを使ってｊｓ側に渡しています。<br>
weatherPoint()のメソッドでは、受け取った緯度と経度をaxios.getの引数に指定しています</p>
<p>今回は緯度と経度を取得しましたが、郵便番号でも首都名でも取得可能です。<br>
ただ、一番精度がいいのは緯度と経度だと思います</p>
<h3>テンプレートの中の解説 その２</h3>

```
  <p class="weather_city">{{ city }}</p>
    <div v-for="post in posts" :key="post.dt">
      <div class="weather_item">
      {{post.dt|calc}}<br>
      {{post.main.temp}}℃<br>
      {{post.weather[0].main}}<br>
        <p v-if="post.weather[0].main === 'Rain'"><i class="fas fa-umbrella fa-3x"></i></p>
        <p v-else-if="post.weather[0].main === 'Clouds'"><i class="fas fa-cloud fa-3x"></i></p>
        <p v-else-if="post.weather[0].main === 'Clear'"><i class="fas fa-sun fa-3x"></i></p>
        <p v-else>該当しなかった<i class="fas fa-cloud-sun fa-3x"></i></p>
      </div>
    </div>
```
<p>openweather.Map　APIから取得したjsonファイルの中身をfor文で回して一つずつ表示させています。</p>
<p>またv-ifを使ってフォントオーサムで取得した画像を入れ替えて表示させています</p>

<h3>メソッドとフィルターズの解説</h3>
```
 methods: {
    weatherPoint:function(){
      let url =this.baseurl + 'lat=' + this.lat + '&lon=' + this.lon + this.units + this.id;
      axios.get(url)
          .then(function (response) {
            this.city = response.data.city.name
            this.posts = response.data.list
          }.bind(this))
          .catch(function (error) {
            console.log(error)
          })
      }
    },
  filters: {
    calc(value) {
      let dateTime = new Date((value) *1000);
      return dateTime.toLocaleString("ja");
    }
  }//filters
```
<p>dataに設定した変数を結合させてaxios.getでjsonファイルを取得しています
filtersを使用することでunixTimeStampで取得した世界標準時間を日本時間に変換しています</p>


<h3>まとめ</h3>
無料の範囲内で天気APIを使ってデータ取得して表示させることができました。
Vueのみであれば上記の形で大丈夫ですが、Laravel等を使用する場合はaxios.getの部分をサーバー側（api.php)で処理しないとうまく動かないので注意してください。

同様の要領で他のAPIからもaxiosを使ってjsonを取得できると思います。