【Vue.js×axios】ホットペッパーグルメサーチAPIを使って非同期に近くのグルメを検索!
最終更新日:2020/01/04
今回実際に作成したのがこちら!
【Vue.js版】近くのお店~フリーワードで –グルメサーチ
このページの仕様は、
- フリーワード検索
- 現在地を測定し、付近のグルメを検索
- 非同期処理
です。
今回はこれベースで解説していきます。
用意するファイルは3つ
- HTML(表示用)
- JavaScript(Vue.js axiosをつかってPHPにリクエスト)
- PHP(リクエストをAPIに送信し、結果を取得して、返す)
まずはAPIキーを取得
APIを利用するためには、まずリクルートWEBサービスに登録して、 APIキーを取得します。
新規登録 | リクルートWEBサービス

メールアドレスだけで登録できるので、すぐ取得できます!
メールアドレスの認証が完了すると、APIキーがメールで届きます。

まずは試しにPHPでグルメ情報を取得
もちろんjsだけでも実装可能ですが、公開するのであれば、APIキーを隠蔽する必要があるのでPHPで作るのが良いでしょう。
自分のAPIキーを他人に使われて、リクルートWEBサービスに危害が加わった時の責任は自分にあるので、APIキーの管理には注意が必要です。
リクエストを送り結果を取得してみる
APIキーをセットして、キーワード『焼肉』を10件分json形式で取得します。
検索クエリ一覧
公式ドキュメント:検索クエリ| APIリファレンス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $baseurl = 'https://webservice.recruit.co.jp/hotpepper/gourmet/v1/'; $keyword = '焼肉'; $params = [ 'key' => '【APIキー】', 'format' => 'json', 'keyword' => $keyword, 'count' => 10, ]; $url = $baseurl . '?' . http_build_query($params, '', '&'); // リクエストを送り結果を取得 $result = file_get_contents($url); // 取得した翻訳結果のjsonをPHPの連想配列に変換 $json = json_decode($result, true); print_r($json); |
結果が、下記レスポンス一覧の構造で配列で取得できたと思います!
レスポンス一覧
公式ドキュメント:レスポンスフィールド|APIリファレンス
掲載したい情報を出力
変数$shops
に結果の店データを格納します。
後はforeach
でループして出力させるだけです!
エラーがあった場合は$json['results']['error']
に値が入ります。
エラーの場合はエラー文を出力して終了させます。
取得件数は$json['results']['results_available']
に値が入ります。
最大100件までしか取得できないのですが、ここの値は全検索結果の数値が入り、検索クエリによっては100件を超えてくる場合もあります。
100件以上の場合は100
とさせます。
結果が無かった場合は見つからなかった分を出力して、終了させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // 店データ $shops = $json['results']['shop']; // エラーがあった場合 if( isset($json['results']['error']) ){ echo $json['results']['error'][0]['message']; exit; } // 取得件数 $results_available = $json['results']['results_available']; if( $results_available > 100 ){ $results_available = 100; } elseif( $results_available == 0 ) { echo '指定の条件ではお店が見つかりませんでした。'; exit; } ?> <?php echo $results_available; ?>件表示中 <?php foreach( $shops as $shop ){ // 一例 echo $shop['name']; // 店名 echo $shop['address']; // 住所 } ?> |
基本はここまでで完了
ここまでで、必要な情報を出力することができたらもう後は、この処理をVueに差し替えやCSSで表示を調整や、
フォームを作って入力に応じて動的に結果を出力してみたりしたらグルメサーチは完成ですね。
この後はVue.jsとaxiosを使って、入力に応じて非同期で検索結果を出力していきます!
Vue.jsとaxiosを使って非同期で結果を出力
Vueとaxiosをそれぞれscriptタグで読み込んでください。
ダウンロード
インストール — Vue.js
https://github.com/axios/axios
jsを用意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | var app = new Vue({ el: '#app', data: { message: 'キーワードを入力や、現在地を計測してお店を検索してください!', // message geoActive: false, //現在地が有効かどうか timer: null, // タイマー keyword: '', // キーワード lat: '', // 緯度 lon: '', // 経度 range: '', // 範囲 gourmetCount: 0, // 検索件数 gourmetList: [] // 検索結果 }, methods: { inputting: function(){ this.getting = false; if (this.timer === null) { this.timer = setTimeout(function () { this.getGourmet(this.keyword, this.lat, this.lon, this.range); clearTimeout(this.timer) this.timer = null }.bind(this), 500) } }, getGeo: function(e){ e.preventDefault(); if( navigator.geolocation ){ let $this = this; navigator.geolocation.getCurrentPosition(function(position){ $this.geoActive = true; $this.lat = position.coords.latitude, // 緯度 $this.lon = position.coords.longitude; // 経度 $this.getGourmet($this.keyword, $this.lat, $this.lon, $this.range); }, function(error){ if( error.code == 1 ){ alert( "位置情報取得が許可されていません。" ); } else if( error.code == 2 ) { alert( "位置情報取得に失敗しました。" ); } else { alert( "タイムアウトしました。" ); } }); } else { alert( "この端末では位置情報取得ができません。" ); } }, getGourmet: function(){ this.getting = false; const params = new URLSearchParams(); params.append('keyword', this.keyword); params.append('lat', this.lat); params.append('lon', this.lon); params.append('range', this.range); let $this = this; axios.post('【PHPファイルのパス】', params).then(function (response) { // 成功時 $this.getting = true; $this.gourmetList = []; let result = response.data.results; $this.gourmetCount = ( result.results_available > 100 ) ? 100 : result.results_available; let shops = result.shop; for( let shop of shops ){ $this.gourmetList.push({ name: shop.name, // 店名 url: shop.urls.pc, // 店舗url logo: shop.logo_image, // ロゴ category: shop.genre.name, // カテゴリ catch: shop.genre.catch, // キャッチコピー photo: shop.photo.pc.l, // メイン画像 address: shop.address, // 住所 map: 'https://maps.google.co.jp/maps?q=' + encodeURI(shop.name), // マップ access: shop.mobile_access, // アクセス open: shop.open, // 営業時間 lunch: shop.lunch, // ランチ card: shop.card, // クレジットカード smoking: shop.non_smoking, // 喫煙・禁煙 wifi: shop.wifi, // wifi parking: shop.parking, // 駐車場 average: shop.budget.average, // 平均予算 memo: shop.budget_memo, // 料金備考 coupon: shop.coupon_urls.pc, // クーポン }) } }).catch(function (error) { // 失敗時 $this.getting = true; $this.message = error; }) } } }); |
data
それぞれで使用していく、データを定義しておきます。
message
は初期メッセージと、エラー時に出力する為に用意します。
検索結果用のdataは、gourmetCount
数値、gourmetList
を配列を空で用意しておきます。
APIリクエスト用の、キーワードや緯度、経度、範囲は空で用意しておきます。
methods
・inputtingメソッド
テキストボックスに入力した0.5秒後に、値を後述のgetGourmet
メソッドに引数で値を渡します。
タイマーを駆使します。
・getGeoメソッド
現在地をJavaScriptを使って取得します。
まず、if( navigator.geolocation )
で取得ができる(許可されている)か判定し、navigator.geolocation.getCurrentPosition
で位置情報を取得し、成功した時と失敗した時の処理を加えていきます。
成功時はdata:lat
とlon
に代入して、後述のgetGourmet
メソッドに引数で値を渡します。
失敗時の受け取った3種類のエラーコードは下記の通りです。
PositionError.code – Web APIs | MDN
注意:thisのスコープ
アロー関数を使用したら問題ないのでしょうが、function()形式で記述しているので、thisのスコープが変化してしまいました。
メソッド内のメソッドに入る前にthisを変数に格納することで回避できます。let $this = this;
・getGourmetメソッド
グルメ情報を取得します。
用意したPHPにリクエストを送って、PHPがAPIにリクエストして返ってきた値をJSで表示させます。
PHPに送るパラメーターをセットします。URLSearchParams()
で用意して、.append('【パラメーター名】', 値);
でパラメーターを一つずつ追加していきます。
あとは、axiosでPHPにpost送信でパラメーターを渡して、結果をgourmetList
に適応したデータをオブジェクトとしてfor
でshopの数繰り返し追加していきます。
この後、結果が格納されたデータgourmetList
をHTML側で出力させます。
エラー時はmessage
に捕捉したエラー文を出力させます。
HTMLを用意
入力フォームと、結果が出力される要素を用意しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | <div id="app"> <div class="p-form" :class="{ 'is-fix': scrollY >= formOffset }"> <div class="p-form-inner"> <input type="text" name="gourmet_keyword" placeholder="フリーワード検索(店名 地名、駅名など)" class="p-keyword" v-model="keyword" @input="inputting"> <a href="" class="p-geo-btn" @click="getGeo">現在地を取得して検索</a> <p class="p-range" v-show="geoActive"><select name="range" v-model="range" @change="getGourmet"> <option value="1">300m圏内</option> <option value="2">500m圏内</option> <option value="3" selected>1000m圏内</option> <option value="4">2000m圏内</option> <option value="5">3000m圏内</option> </select></p> </div> <div class="p-result-txt m-normal-txt"> <p v-if="keyword">キーワード:『{{ keyword }}』</p> <p v-if="range == 1">現在地から300m圏内</p> <p v-else-if="range == 2">現在地から500m圏内</p> <p v-else-if="range == 4">現在地から2000m圏内</p> <p v-else-if="range == 5">現在地から3000m圏内</p> <p v-show="geoActive" v-else>現在地から1000m圏内</p> </div> </div> <p class="m-normal-txt" v-if="gourmetList.length == 0">{{ message }}</p> <div class="p-result-area" v-if="gourmetList.length > 1"> <p class="m-normal-txt tar">{{ gourmetCount }}件表示中</p> <ul class="p-list"> <li v-for="item of gourmetList"> <div class="p-name-wrap"> <p class="p-shop-logo"><img :src="item.logo" alt=""></p> <div class="p-name-content"> <p class="p-category">{{ item.category }}</p> <p class="p-catch">{{ item.catch }}</p> <p class="p-name">{{ item.name }}</p> </div> </div> <div class="p-content"> <div class="p-main-img"> <p><a :href="item.category" target="_blank" rel="noopener noreferrer"> <img :src="item.photo" :alt="item.name"><br> <span class="mt20 spmt20 m-blank">店舗ページを見る</span> </a></p> </div> <table class="p-table"> <tr> <th>住所</th> <td>{{ item.address }}<br> <a :href="item.map" target="_blank" rel="noopener noreferrer" class="m-txt-hover p-map-link" class="m-blank">Google Mapで見る</a></td> </tr> <tr> <th>アクセス</th> <td>{{ item.access }}</td> </tr> <tr> <th>営業時間</th> <td>{{ item.open }}</td> </tr> <tr> <th>ランチ</th> <td>{{ item.lunch }}</td> </tr> <tr> <th>クレジット<br class="nopc">カード</th> <td>{{ item.card }}</td> </tr> <tr> <th>禁煙・喫煙</th> <td>{{ item.smoking }}</td> </tr> <tr> <th>Wi-Fi</th> <td>{{ item.wifi }}</td> </tr> <tr> <th>駐車場</th> <td>{{ item.parking }}</td> </tr> <tr> <th>平均予算</th> <td>{{ item.average }}</td> </tr> <tr v-if="item.memo"> <th>料金備考</th> <td>{{ item.memo }}</td> </tr> <tr> <th>クーポン</th> <td><a :href="item.coupon" target="_blank" rel="noopener noreferrer" class="m-blank m-txt-hover">クーポンを見る</a></td> </tr> </table> </div> </li> </ul> </div> </div><!-- app --> |
v-model
v-model
で値を同期させます。
入力に応じて入力した値を出力させます。
v-if
で値があるか判定し、あったら出力させます。
範囲に関しては、現在地(geoActive
)が有効時に出力させます。
1 2 3 4 5 6 | <p v-if="keyword">キーワード:『{{ keyword }}』</p> <p v-if="range == 1">現在地から300m圏内</p> <p v-else-if="range == 2">現在地から500m圏内</p> <p v-else-if="range == 4">現在地から2000m圏内</p> <p v-else-if="range == 5">現在地から3000m圏内</p> <p v-show="geoActive" v-else>現在地から1000m圏内</p> |
@input、@click、@change
入力、クリック、セレクトボックスを選択した時のイベントを指定します。
入力時にinputtingメソッド発火 @input="inputting"
クリック時にgetGeoメソッド発火 @click="getGeo"
チェンジ時にgetGourmetメソッド発火 @change="getGourmet"
どちらのタイミングでもグルメ情報を取得し、出力します。
v-for
v-for
で取得したデータ:gourmetList
をitem
に代入して、出力させます。
また、v-if
で結果の有無でHTMLの出力を分岐させます。
エラー時はmessage
でエラー文を出力させます。
PHPを用意
APIにリクエストし、結果を返す用のPHPを用意します。
APIキーを隠蔽するためにも、PHPを挟むのが良いでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | $keyword = $_POST['keyword'] ? $_POST['keyword'] : ''; $lat = $_POST['lat'] ? $_POST['lat'] : ''; $lon = $_POST['lon'] ? $_POST['lon'] : ''; $range = $_POST['range'] ? $_POST['range'] : ''; $baseurl = 'https://webservice.recruit.co.jp/hotpepper/gourmet/v1/'; $params = [ 'key' => '【APIキー】', 'format' => 'json', 'keyword' => $keyword, 'count' => 100, 'lat' => $lat, 'lng' => $lon, 'range' => $range, ]; $url = $baseurl . '?' . http_build_query($params, '', '&'); // リクエストを送り結果を取得 $result = file_get_contents($url); // 結果を出力 header("Content-Type: text/javascript; charset=utf-8"); echo $result; exit(); |
POSTでJSから値が渡されるので、それをつかってAPIにリクエストを送ります。
返ってきたjsonをjs側に渡してあげます。
最終 完成版ソース
HTML
ローディングアニメーションや、入力中アニメーション、スクロールで検索フォーム追従なども追加しました。
主にv-bind:class
でclassを出し分けています。
ローディングは下記参考サイトを使うのがおススメです!
SpinKit | Simple CSS Spinners
Loaders.css
API利用規約で、ホットペッパーのクレジット表記が義務付けられているの注意してください。
下記からHTMLをコピーできるのでそれを張り付けましょう。
クレジット表示について
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | <div id="app"> <div class="spinner" v-show="loading"> <div class="double-bounce1"></div> <div class="double-bounce2"></div> </div> <div class="l-content"> <div class="p-wrap" v-show="!loading"> <p class="tar"><a href="https://webservice.recruit.co.jp/"><img src="https://webservice.recruit.co.jp/banner/hotpepper-s.gif" alt="ホットペッパー Webサービス" width="135" height="17" title="ホットペッパー Webサービス"></a></p> <div class="p-form" :class="{ 'is-fix': scrollY >= formOffset }"> <div class="p-form-inner"> <input type="text" name="gourmet_keyword" placeholder="フリーワード検索(店名 地名、駅名など)" class="p-keyword" v-model="keyword" @input="inputting"> <a href="" class="p-geo-btn" @click="getGeo">現在地を取得して検索</a> <p class="p-range" v-show="geoActive"><select name="range" v-model="range" @change="getGourmet"> <option value="1">300m圏内</option> <option value="2">500m圏内</option> <option value="3" selected>1000m圏内</option> <option value="4">2000m圏内</option> <option value="5">3000m圏内</option> </select></p> </div> <div class="p-result-txt m-normal-txt"> <p v-if="keyword">キーワード:『{{ keyword }}』</p> <p v-if="range == 1">現在地から300m圏内</p> <p v-else-if="range == 2">現在地から500m圏内</p> <p v-else-if="range == 4">現在地から2000m圏内</p> <p v-else-if="range == 5">現在地から3000m圏内</p> <p v-show="geoActive" v-else>現在地から1000m圏内</p> </div> </div> <div class="p-loader" :class="{ 'is-hide': getting }"><div></div><div></div><div></div></div> <p class="m-normal-txt" v-if="gourmetList.length == 0">{{ message }}</p> <div class="p-result-area" :class="{ 'is-fix': scrollY >= formOffset }" v-if="gourmetList.length > 1"> <p class="m-normal-txt tar">{{ gourmetCount }}件表示中</p> <ul class="p-list"> <li v-for="item of gourmetList"> <div class="p-name-wrap"> <p class="p-shop-logo"><img :src="item.logo" alt=""></p> <div class="p-name-content"> <p class="p-category">{{ item.category }}</p> <p class="p-catch">{{ item.catch }}</p> <p class="p-name">{{ item.name }}</p> </div> </div> <div class="p-content"> <div class="p-main-img"> <p><a :href="item.category" target="_blank" rel="noopener noreferrer"> <img :src="item.photo" :alt="item.name"><br> <span class="mt20 spmt20 m-blank">店舗ページを見る</span> </a></p> </div> <table class="p-table"> <tr> <th>住所</th> <td>{{ item.address }}<br> <a :href="item.map" target="_blank" rel="noopener noreferrer" class="m-txt-hover p-map-link" class="m-blank">Google Mapで見る</a></td> </tr> <tr> <th>アクセス</th> <td>{{ item.access }}</td> </tr> <tr> <th>営業時間</th> <td>{{ item.open }}</td> </tr> <tr> <th>ランチ</th> <td>{{ item.lunch }}</td> </tr> <tr> <th>クレジット<br class="nopc">カード</th> <td>{{ item.card }}</td> </tr> <tr> <th>禁煙・喫煙</th> <td>{{ item.smoking }}</td> </tr> <tr> <th>Wi-Fi</th> <td>{{ item.wifi }}</td> </tr> <tr> <th>駐車場</th> <td>{{ item.parking }}</td> </tr> <tr> <th>平均予算</th> <td>{{ item.average }}</td> </tr> <tr v-if="item.memo"> <th>料金備考</th> <td>{{ item.memo }}</td> </tr> <tr> <th>クーポン</th> <td><a :href="item.coupon" target="_blank" rel="noopener noreferrer" class="m-blank m-txt-hover">クーポンを見る</a></td> </tr> </table> </div> </li> </ul> </div> </div> </div><!-- l-content --> </div><!-- app --> |
Javascript
算出プロパティでフォームの位置を計算。
スクロールイベントや、ローディング系も入っているので参考にどうぞ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | var app = new Vue({ el: '#app', data: { loading: true, // 読み込み時のローディングアイコン message: 'キーワードを入力や、現在地を計測してお店を検索してください!', // message geoActive: false, //現在地が有効かどうか getting: true, // 取得中アイコン scrollY: 0, // スクロール値 timer: null, // タイマー keyword: '', // キーワード lat: '', // 緯度 lon: '', // 経度 range: '', // 範囲 gourmetCount: 0, // 検索件数 gourmetList: [] // 検索結果 }, computed: { formOffset: function(){ // フォームの位置 var rect = document.querySelector('.p-form').getBoundingClientRect(); return window.pageYOffset + rect.top; } }, created: function(){ // イベント登録 window.addEventListener('scroll', this.scEvent); }, beforeDestroy: function(){ // イベント解除 window.removeEventListener('scroll', this.scEvent); }, methods: { //scイベントで現在のスクロール値を取得 scEvent: function() { if (this.timer === null) { this.timer = setTimeout(function () { this.scrollY = window.scrollY clearTimeout(this.timer) this.timer = null }.bind(this), 50) } }, inputting: function(){ this.getting = false; if (this.timer === null) { this.timer = setTimeout(function () { this.getGourmet(this.keyword, this.lat, this.lon, this.range); clearTimeout(this.timer) this.timer = null }.bind(this), 500) } }, getGeo: function(e){ e.preventDefault(); if( navigator.geolocation ){ let $this = this; navigator.geolocation.getCurrentPosition(function(position){ $this.geoActive = true; $this.lat = position.coords.latitude, // 緯度 $this.lon = position.coords.longitude; // 経度 $this.getGourmet($this.keyword, $this.lat, $this.lon, $this.range); }, function(error){ if( error.code == 1 ){ alert( "位置情報取得が許可されていません。" ); } else if( error.code == 2 ) { alert( "位置情報取得に失敗しました。" ); } else { alert( "タイムアウトしました。" ); } }); } else { alert( "この端末では位置情報取得ができません。" ); } }, getGourmet: function(){ this.getting = false; const params = new URLSearchParams(); params.append('keyword', this.keyword); params.append('lat', this.lat); params.append('lon', this.lon); params.append('range', this.range); let $this = this; axios.post('【PHPファイルのパス】', params).then(function (response) { // 成功時 $this.getting = true; $this.gourmetList = []; let result = response.data.results; $this.gourmetCount = ( result.results_available > 100 ) ? 100 : result.results_available; let shops = result.shop; for( let shop of shops ){ $this.gourmetList.push({ name: shop.name, // 店名 url: shop.urls.pc, // 店舗url logo: shop.logo_image, // ロゴ category: shop.genre.name, // カテゴリ catch: shop.genre.catch, // キャッチコピー photo: shop.photo.pc.l, // メイン画像 address: shop.address, // 住所 map: 'https://maps.google.co.jp/maps?q=' + encodeURI(shop.name), // マップ access: shop.mobile_access, // アクセス open: shop.open, // 営業時間 lunch: shop.lunch, // ランチ card: shop.card, // クレジットカード smoking: shop.non_smoking, // 喫煙・禁煙 wifi: shop.wifi, // wifi parking: shop.parking, // 駐車場 average: shop.budget.average, // 平均予算 memo: shop.budget_memo, // 料金備考 coupon: shop.coupon_urls.pc, // クーポン }) } }).catch(function (error) { // 失敗時 $this.getting = true; $this.message = error; }) } }, mounted: function() { setTimeout(() => { this.loading = false; }, 1000); } }); |
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php $keyword = $_POST['keyword'] ? $_POST['keyword'] : ''; $lat = $_POST['lat'] ? $_POST['lat'] : ''; $lon = $_POST['lon'] ? $_POST['lon'] : ''; $range = $_POST['range'] ? $_POST['range'] : ''; $baseurl = 'https://webservice.recruit.co.jp/hotpepper/gourmet/v1/'; $params = [ 'key' => '【APIキー】', 'format' => 'json', 'keyword' => $keyword, 'count' => 100, 'lat' => $lat, 'lng' => $lon, 'range' => $range, ]; $url = $baseurl . '?' . http_build_query($params, '', '&'); // リクエストを送り結果を取得 $result = file_get_contents($url); // 結果を出力 header("Content-Type: text/javascript; charset=utf-8"); echo $result; exit(); |
完成サイト
【Vue.js版】近くのお店~フリーワードで –グルメサーチ