🤭
Vue+ぐるなびAPIを使ってレストラン情報を取得した
はじめに
Vue(axios)を使ってAPIからjsonファイルを取得する方法の一例を紹介します。
ぐるなびAPIは無料で始められるので、お勉強用にとてもいいと思います。
最終的にできるもの
環境
無駄なパッケージたくさんあると思います。
エディタはphpstormを使っています。
pakage.json
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"dev": "webpack"
},
"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"
},
ディレクトリ構成
-src
--conponent
--Gurunabi.vue
App.vue
main.js
conponent Vueファイル以外のファイル状況
App.vue
<template>
<div id="app">
<Gurunabi></Gurunabi>
</div>
</template>
<script>
import Gurunabi from "@/components/Gurunabi";
export default {
components:{
Gurunabi,
},
}
</script>
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
ぐるなびAPIについて
こちらのリンクからjsonファイルのテストツールがあるので受け取るjson形式を確認することができます。
(地味にこれ便利ですよね)
Gurunabi.vue
<template>
<div>
<div>
<h3>近くの飲食店を検索できます</h3>
<input type="text" id="name" v-model="name" placeholder="店名"><br>
<p v-if="name">
<button @click="searchShop" class="shop-get-button">検索</button>
</p>
<input type="text" id="freeWord" v-model="freeWord" placeholder="フリーワード"><br>
<p v-if="freeWord">
<button @click="searchFree" class="shop-get-button">検索</button>
</p>
<hr>
</div>
<h3>検索結果を表示</h3>
<div v-for="info in shopInfo" :key="info.id">
<div class="main-block">
<div class="top-block">
<div class="side-pic">
<a :href="info.url" target="_blank">
<img :src=info.image_url.shop_image1 alt="">
</a>
</div>
<div class="comment-area">
<h3>{{info.name}}</h3>
<p><b>{{info.address}}</b></p>
<p><b>{{info.tel}}</b></p>
<p><b>{{info.opentime}}</b></p>
</div>
</div>
<div class="pr-comment">
<p>{{info.pr.pr_long}}</p>
<button :href=info.url target="_blank" class="shop-get-button">お店の予約</button>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data(){
return{
name:'',//入力値から取得
freeWord:'',//入力値から取得
baseurl:'https://api.gnavi.co.jp/RestSearchAPI/v3/?',
id:'keyid=APIKEY',
shopInfo:[],
}
},
methods:{
searchShop:function(){
let url= this.baseurl + this.id + '&name=' + this.name;
axios.get(url)
.then(function (response) {
this.shopInfo = response.data.rest
}.bind(this))
.catch(function (error) {
console.log(error);
alert('検索結果は見つかりませんでした');
})
},
searchFree:function(){
let url1= this.baseurl + this.id + '&freeword=' + this.freeWord;
axios.get(url1)
.then(function (response) {
this.shopInfo = response.data.rest
}.bind(this))
.catch(function (error) {
console.log(error);
alert('検索結果は見つかりませんでした');
})
},
},
}
</script>
<style scoped>
.shop-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;
}
.shop-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);
}
.main-block{
background: #fff;
width:960px;
margin:100px auto;
border: 0.5px solid #2c3e50;
}
.top-block{
overflow: hidden;
}
.side-pic{
width:30%;
float: left;
}
.side-pic:hover{
cursor: pointer;
}
.comment-area{
width:70%;
box-sizing: border-box;
padding:29px;
float:left;
text-align: left;
}
.pr-comment{
width:100%;
box-sizing: border-box;
padding:20px;
background: #f6f5f4;
}
input[type="text"]{
width:30%;
padding:10px;
border: .5px solid #2c3e50;
}
</style>
主要箇所をざっくりと説明
<input type="text" id="name" v-model="name" placeholder="店名"><br>
------------------------------------------------------------------------
data(){
return{
name:'',//入力値から取得
------------------------------------------------------------------------
let url= this.baseurl + this.id + '&name=' + this.name;
axios.get(url)
テキスト入力した値をURLの引数にして、APIからjson形式で取得しています。
axios.get(url)
.then(function (response) {
this.shopInfo = response.data.rest
------------------------------------------------------------------------
data(){
return{
name:'',//入力値から取得
freeWord:'',//入力値から取得
baseurl:'https://api.gnavi.co.jp/RestSearchAPI/v3/?',
id:'keyid=API KEY,
shopInfo:[],
}
------------------------------------------------------------------------
<div v-for="info in shopInfo" :key="info.id">
<div class="main-block">
<div class="top-block">
<div class="side-pic">
<a :href="info.url" target="_blank">
<img :src=info.image_url.shop_image1 alt="">
</a>
</div>
<div class="comment-area">
<h3>{{info.name}}</h3>
<p><b>{{info.address}}</b></p>
<p><b>{{info.tel}}</b></p>
<p><b>{{info.opentime}}</b></p>
</div>
</div>
<div class="pr-comment">
<p>{{info.pr.pr_long}}</p>
<button :href=info.url target="_blank" class="shop-get-button">お店の予約</button>
配列形式で受け取った値をtemplate内でv-forを使って回して動的に表示しています。
"info.url"などはパラメータのためv-bindを使用して動的に表示させています。
つまづいたPOINT
- v-bindをあまり理解できておらず、template内で表示させるときに<img src="{{info.url}}" >とやってしまっていました。
最初はbsse64かな?と思ったりしてつまづきました。
Discussion