일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- js 반복문
- CentOS8
- 아두이노 https
- 라즈베리파이
- redirect
- 아두이노 https post
- js 내부함수 반복문
- 아두이노 ESP8266
- Raspbian
- 구글 클라우드 플랫폼
- 아두이노 fingerprint
- MariaDB
- Centos Node js
- 아두이노 DB
- js for 반복문
- 리디렉트
- 라즈베리파이 3b+
- 리다이렉트
- js 내부함수
- Apache
- 리디렉션
- 아두이노
- Today
- Total
dinist
[Laravel + tailwindcss + Vue.js] 날씨 페이지 만들기 - 2 본문
이미 페이지를 완성한 후 게시글을 작성하는 것이므로 자세한 사진설명이 생략되어 있습니다.
이 포스팅에서 사용하는 tailwindcss 버전은 v2 버전입니다. 만약 IE를 지원해야 한다면
es6-promise 와 tailwindcss 버전 v1을 사용해야합니다.
v1와 v2간의 기능 차이가 있을 수 있습니다.
[Laravel + tailwindcss + Vue.js] 날씨 페이지 만들기 - 1
https://dinist.tistory.com/36?category=1223053
지난 1편 작성 후 2주가 지난 뒤에야 글을 씁니다. 바쁜때도 있었고, 귀찮아서 미루다보니 이렇게 2주가 지났습니다.
반성해야겠어요
이제 본론으로 들어가봅시다.
지난 1편에는기본적인 설치를 다루었고, 2편에서는 디자인과 실행을 다룰 예정입니다.
디자인은 대략적인 설명만 진행할 예정입니다.
/resources/js/app.js 파일을 보시면
// Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('vue-weather', require('./components/VueWeather.vue').default);
example-component를 vue-weather 로 변경해줍니다.
이후 /resources/js/components/ExampleComponent.vue 파일을 /resources/js/components/VueWeather.vue 파일로 이름을 변경합니다.
이후 /resources/view/welcome.blade.php 파일에서 <Example-component>를 <vue-weather>로 변경해줍니다.
이후 localhost:3000 또는 8000으로 접속해서 페이지가 정상적으로 표시된다면 변경사항 적용이 완료된 것입니다.
우선 VueWeather.vue 파일의 <template> 부분을 다음과같이 변경합니다.
<template>
<div class="weather-container">
<div id="menu_wrap" class="bg-transparent text-black w-128 px-1 py-2">
<div class="option">
<div>
<form id="search" @submit="searchPlaces" class="flex justify-end items-center px-0.5">
<input type="text" id="keyword" size="20" class="w-full px-2 py-1 rounded-lg outline-none" placeholder="장소명 입력">
<button type="submit" class="absolute mr-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</button>
</form>
</div>
</div>
</div>
<div id="list" class="absolute w-128 rounded-t-md">
<ul id="placesList" class="hidden bg-yellow-50 rounded-t-lg min-h-640"></ul>
<div id="pagination" class="hidden py-2 bg-yellow-50 rounded-b-lg"></div>
</div>
<div class="top-wrapper w-128 flex justify-between px-6 py-8 bg-gray-800 rounded-t-lg">
<div class="temperature-side">
<div class="live-temperature text-6xl font-bold">{{weatherdata.temp}}°C</div>
<div class="fells-like-temperature my-2">체감 기온 {{weatherdata.fells_like}}°C</div>
</div>
<div class="weather-stat-side flex justify-center flex-col w-1/2">
<div>{{weatherdata.weather}}</div>
<div>{{location.name}}</div>
</div>
<div class="weather-icon-side flex items-center">
<img :src="weatherdata.icon ? 'http://openweathermap.org/img/wn/'+weatherdata.icon+'.png' : '' ">
</div>
</div>
<div class="middle w-128 px-6 py-2 bg-gray-600 rounded-b-lg h-30r">
<div class="middle-inside flex justify-between items-center px-6 my-2" v-for="(day,idx) in daily_weather_data" :key="day.dt">
<div class="day">
{{new Date(day.dt * 1000).getDate()+" "+days[new Date(day.dt * 1000).getDay()]}}
</div>
<div class="icon">
<img :src="day.weather[0].icon ? 'http://openweathermap.org/img/wn/'+day.weather[0].icon+'.png' : '' ">
</div>
<div>
{{new Date(day.sunrise * 1000).getHours()+" : "}}{{new Date(day.sunrise * 1000).getMinutes() < 10 ? '0' : ''}}{{new Date(day.sunrise * 1000).getMinutes()}}
</div>
<div>
{{new Date(day.sunset * 1000).getHours()+" : "}}{{new Date(day.sunset * 1000).getMinutes() < 10 ? '0' : ''}}{{new Date(day.sunset * 1000).getMinutes()}}
</div>
<div class="temperature">
<div>
{{ Math.round(day.temp.min) }} °C
</div>
<div>
{{ Math.round(day.temp.max) }} °C
</div>
</div>
</div>
</div>
</div>
</template>
이후 페이지를 보면 정상작동 하지 않을것입니다.
당연합니다. 스크립트 코드는 작성하지 않았기 때문입니다.
그리고 1편에 링크한 유튜브 영상에서는 장소검색을 위해
Algolia Places를 이용했는데 이 서비스가 2022년 5월말에 서비스 종료 예정이랍니다.
관련링크 : https://www.algolia.com/blog/product/sunsetting-our-places-feature/
그래서 대안으로 여러개를 찾아봤지만 국내한정으로 이용한다는 가정으로 카카오맵 API를 이용하기로 결정했습니다.
이에따라 카카오맵 API를 이용하기 위해 KAKAO JS KEY 가 필요해졌네요
카카오계정으로 로그인 후
https://developers.kakao.com/console/app
이곳에서 애플리케이션을 하나 추가해줍시다.
이후 애플리케이션 페이지로 접속해 요약정보를 보면 JavaScript 키가 있습니다.
이것을 복사해주시고!
프로젝트 루트폴더에 보시면 .env라는 파일이 있습니다.
하단에 다음과 같이 추가해줍니다.
MIX_KAKAO_JS_KEY=여러분의 KAKAO JS KEY
왜 앞에 MIX_를 붙였는지 설명 해드리겠습니다. 우리는 Laravel Mix를 사용중인 상태인데 이 Laravel Mix를 사용하면 Vue 파일에서 Laravel의 .env 변수에 접근할 수 있습니다. 단 접두어가 MIX_로 시작해야 합니다. 이러한 MIX_ 로 시작하는 변수는 Vue의 script 코드에서 process.env.MIX_변수이름 을 통해 해당 값에 접근 할 수 있습니다.
이번 프로젝트에서는 카카오맵 API 활용을 위해 해당 MIX 변수를 사용하게 됩니다.
날씨정보는 openweathermap 을 이용합니다. 이 서비스도 마찬가지로 API KEY 가 필요하며 .env파일에 변수로 추가해야합니다.
openweathermap 사용법을 알려드립니다.
https://openweathermap.org/api
이 사이트에 우선 가입을 하고, One Call API 의 Free로 API 신청을 합니다.
이후 https://home.openweathermap.org/api_keys 에서 API키를 확인하실 수 있습니다.
API키가 발급되었다 해서 바로 사용이 가능한 것은 아닌것 같습니다. 20분정도 이후에 서비스 이용이 가능한것으로 보입니다.
API키를 복사해서 .env 파일에 다음과같이 추가해줍니다.
OPENWEATHER_KEY=여러분의 OPENWEATHER KEY
그리고 /config/services.php 파일의 리턴 배열 내에 다음 내용을 추가해 줍니다.
'weather' => [
'key' => env('OPENWEATHER_KEY'),
],
추가하면 이런식이 됩니다.
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
],
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'weather' => [
'key' => env('OPENWEATHER_KEY'),
],
이제 날씨 정보를 가져올 API 페이지를 만들어봅시다.
/routes/api.php 파일을 열어봅시다. 그리고 하단에 다음 내용을 추가합니다.
Route::get('weather', function () {
$service_key = config('services.weather.key');
$lat = request('lat');
$lng = request('lng');
$url = "https://api.openweathermap.org/data/2.5/onecall?lang=kr&lat=$lat&lon=$lng&exclude=minutely,hourly&units=metric&appid=$service_key";
$res = Http::get($url);
return $res->json();
});
서비스키는 방금 /config/services.php 파일에 추가한 .env 변수를 가져오는 값이 되며,
lat(위도), lng(경도)를 변수로 저장 후 Http:get 요청 후 이를 json으로 반환하는 방식입니다.
Route::get('weather' 라고 했으니 /api/weather 페이지로 get요청시 위 함수가 실행될 것입니다.
분단위, 1시간단위는 제외하고 온도단위는 섭씨단위로 지정했습니다.
혹시 여러분들은 다른기준 및 추가 데이터를 가져오기 원하신다면 아래 API Doc 페이지 주소를 안내해드리니 해당 페이지를 참고하셔서 Request URL을 구성하시면 되겠습니다.
https://openweathermap.org/api/one-call-api
그리고 로딩 효과도 추가해주면 좋겠지요?
로딩 효과도 추가해봅시다. 로딩효과 이미지는 아래 사이트에서 만들었습니다.
svg로 다운 받고 코드를 복사하여 vue 컴포넌트를 하나 더 만들었습니다.
/resources/js/components/LoadImg.vue 파일을 만듭니다.
<template>
<!-- [ldio] generated by https://loading.io/ -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto; animation-play-state: running; animation-delay: 0s;" width="6.2rem" height="6.2rem" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="84" cy="50" r="10" fill="#e15b64" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="0.43859649122807015s" calcMode="spline" keyTimes="0;1" values="10;0" keySplines="0 0.5 0.5 1" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="fill" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="discrete" keyTimes="0;0.25;0.5;0.75;1" values="#e15b64;#abbd81;#f8b26a;#f47e60;#e15b64" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle>
<circle cx="16" cy="50" r="10" fill="#e15b64" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="0s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle>
<circle cx="50" cy="50" r="10" fill="#f47e60" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.43859649122807015s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.43859649122807015s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle>
<circle cx="84" cy="50" r="10" fill="#f8b26a" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.8771929824561403s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-0.8771929824561403s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle>
<circle cx="16" cy="50" r="10" fill="#abbd81" style="animation-play-state: running; animation-delay: 0s;">
<animate attributeName="r" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="0;0;10;10;10" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-1.3157894736842104s" style="animation-play-state: running; animation-delay: 0s;"></animate>
<animate attributeName="cx" repeatCount="indefinite" dur="1.7543859649122806s" calcMode="spline" keyTimes="0;0.25;0.5;0.75;1" values="16;16;16;50;84" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" begin="-1.3157894736842104s" style="animation-play-state: running; animation-delay: 0s;"></animate>
</circle>
</svg>
</template>
저장 후 VueWeather.vue 파일에 방금 생성한 LoadImg.vue 파일을 가져옵니다.
import LoadImg from './LoadImg.vue';
export default{
components : {
LoadImg
}
}
components에 LoadImg를 추가해줍니다.
스크립트 코드는 은근히 길어서 이곳에 첨부하기엔 너무 포스팅이 길어질것 같습니다.
완성된 프로젝트의 github 링크를 달아드릴테니 코드를 확인해주세요!
https://github.com/devdinist/Laravel_Vue_Weather
궁금하신점이 있으면 댓글 달아주세요
하지만 답글을 언제 달지는 장담할 수 없습니다.. ㅠ
'Web > PHP' 카테고리의 다른 글
PHP - Enum 사용하기 2 (0) | 2023.05.24 |
---|---|
PHP - Enum 사용하기 (0) | 2023.05.24 |
[PhpStorm] 라라벨 serve , npm dev 설정 추가 (0) | 2023.01.17 |
[Laravel] Laravel Sail 설치하기 (0) | 2021.09.23 |
[Laravel + tailwindcss + Vue.js] 날씨 페이지 만들기 - 1 (0) | 2021.08.14 |