- 投稿日:2019-10-26T21:37:55+09:00
Vue.jsで、食べログとかによくある予約表を作ってみた
はじめに
フロント経験は、JavaScriptとReactを触ったことがある程度です。数ヶ月後に業務で使用することを目指し、独学でVue.jsの学習をしています。
今回は、「とりあえず動く」を目標に、食べログやサロン予約ページによくある予約表を作ってみました。
初学者の方の役に立てば幸いです。エンジニアの方からは、コードに関しての指摘修正など頂けるととても嬉しいです。
作ったもの
主な機能は、以下の通りです。
- 予約一覧
- 1週間ごとの表示切替
- 選択日程表示
- moment.jsで日付管理
なお、表示のためにダミーデータを入れています。
環境
npm 6.7.0 Node.js 10.15.1 Vue.js 2.6.10 Vue CLI 3.12.0主要コード
※スタイルは省略しています。
src/App.vue<template> <div id="app"> <Reservation v-on:send-reservation="text = $event"></Reservation> <p>{{text}}</p> </div> </template> <script> import Reservation from './components/Reservation.vue' export default { name: 'app', data() { return { text: "日程未選択です" } }, components: { Reservation } }; </script>src/components/Reservation.vue<template> <div> <h2>予約一覧</h2> <p> <button @click="movePreviousWeek">前の1週間</button> <strong>{{startDate.format('MM')}}月</strong> <button @click="moveNextWeek">後の1週間</button> </p> <table border="1" align="center"> <thead> <tr> <td></td> <template v-for="date in dateList"> <th :key="date"> {{ date }} </th> </template> </tr> </thead> <tbody> <template v-for="hourlyWorkList in hourlyWorkList"> <tr :key="hourlyWorkList.time"> <td>{{hourlyWorkList.time}}</td> <td v-for="(work, i) in hourlyWorkList.workList" :key="hourlyWorkList.time + '_' + i"> <a @click="sendReservation(dateList[i], hourlyWorkList.time, work)"> {{ showWorkStatus(work) }} </a> </td> </tr> </template> </tbody> </table> <hr> </div> </template> <script> import moment from 'moment' moment.locale('ja'); export default { data(){ return { dateList: [], weekNumber: 7, hourlyWorkList: [] } }, created() { this.setDateList(this.startDate) this.setHourlyWorkList() }, computed: { startDate: { get() { return moment() }, set(date) { this.setDateList(date) this.setHourlyWorkList() } } }, methods: { moveNextWeek() { this.startDate = this.startDate.add(this.weekNumber, 'day') }, movePreviousWeek() { this.startDate = this.startDate.subtract(this.weekNumber, 'day') }, setDateList() { var dateListClone = this.dateList dateListClone = [] var date = moment(this.startDate) dateListClone.push(date.format('MM/DD(dd)')) for ( var i = 0; i < (this.weekNumber - 1); i++ ) { dateListClone.push(date.add(1, 'day').format('MM/DD(dd)')) } this.dateList = dateListClone }, setWorkList() { //ダミー配列データ生成 var array = []; for (let i = 0; i < this.weekNumber; i++) { array.push(Math.random() < 0.5); } return array }, setHourlyWorkList() { this.hourlyWorkList = [ { time: "11:00" , workList: this.setWorkList() }, { time: "12:00" , workList: this.setWorkList() }, { time: "13:00" , workList: this.setWorkList() }] }, sendReservation(date, time, work) { var text = "" if (work == true) { text = date + time } else { text = "この日程は選択できません。" } this.$emit("send-reservation", text) }, showWorkStatus(work) { return work ? "o" : "x" } } }; </script>※全てのコードはGithubに公開しています。(2019/10/26現在)
最後に
Vue.jsは理解がかなり簡単かつ直感的に書けるので、学習しやすい印象でした。しかし、コンポーネント間の値の受け渡しや、算出プロパティ、メソッドなど理解が難しい部分もありました。
「とりあえず動く」を重視して実装してみたので、より綺麗に素早くコードを書けるようにさらに学習を進めます。
参考
Udemy Vue JS 2 入門 完全パック - もう他の教材は買わなくてOK! (Vue Router, Vuex含む
- 投稿日:2019-10-26T16:01:03+09:00
Vue.js と Leaflet で地図を表示するまで
概要
地図のためののライブラリであるLeafletとそのVue.js用のラッパーVue2Leafletを使ってVueで地図を表示させます。
準備
まず適当なプロジェクトを作成してライブラリをインストールします。
作成にはvue-cliを使っています。vue create leaflet-vue && cd leaflet-vue npm install vue2-leaflet leaflet --save地図を表示する
まずはエントリーポイントの
main.jsで以下を追記してcssファイルを読み込ませます。main.jsimport 'leaflet/dist/leaflet.cssApp.vueを以下のように編集します。
ここで注意すべきは
styleのheight属性です。q
これを指定しなかったり、height: 100%;のようにピクセルで指定しないと地図が表示されません。App.vue<template> <div id="app"> <l-map ref="map" style="height: 600px;" :zoom="zoom" :center="center"> <l-tile-layer :url="url"></l-tile-layer> </l-map> </div> </template> <script> import { LMap, LTileLayer } from "vue2-leaflet"; export default { name: "app", components: { LMap, LTileLayer }, data() { return { url: "http://{s}.tile.osm.org/{z}/{x}/{y}.png", zoom: 8, center: [35.693825, 139.703356] }; } }; </script>サークルを表示する
地図上にサークルを表示してみます。
サークルを表示するにはLCircleコンポーネントを使用します。App.vue<template> <div id="app"> <l-map ref="map" style="height: 600px;" :zoom="zoom" :center="center"> <l-tile-layer :url="url"></l-tile-layer> <l-circle :lat-lng="center" :radius="1000" :color="'red'"></l-circle> </l-map> </div> </template> <script> import { LMap, LTileLayer, LCircle } from "vue2-leaflet"; export default { name: "app", components: { LMap, LTileLayer, LCircle }, // ... // 以下略 }; </script>マーカーを表示する
LMarkerでマーカーを表示できます。
マーカーを使用するにはコンポーネントを読み込むだけでなくもう一手間かける必要があります。
main.jsに以下を追記します。main.jsimport L from 'leaflet'; import 'leaflet/dist/leaflet.css'; delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'), iconUrl: require('leaflet/dist/images/marker-icon.png'), shadowUrl: require('leaflet/dist/images/marker-shadow.png'), });あとはサークルのときと同じです。
App.vue<template> <div id="app"> <l-map ref="map" style="height: 600px;" :zoom="zoom" :center="center"> <l-tile-layer :url="url"></l-tile-layer> <l-marker :lat-lng="center"></l-marker> </l-map> </div> </template> <script> import { LMap, LTileLayer, LMarker } from "vue2-leaflet"; export default { name: "app", components: { LMap, LTileLayer, LMarker }, // ... // 以下略 }; </script>
- 投稿日:2019-10-26T09:06:29+09:00
Nuxt.js(SPA)+FirebaseのWebアプリで初マイグレーションをしてけど、いろいろ失敗した話。。
これはただの失敗談です。。役に立つかわからないけど、誰かの参考になるといいな。。
Nuxt.js+Firebaseで開発したWebサービスをリリースして2ヶ月目くらい。
サービス止めて、初マイグレーションしてときの失敗談です。サービスを止めてやりたかったこと
いままではちょこっとした変更が多かったため、
サービスを止める必要なく、Nuxtアプリの更新だけで十分でしたが、
新しい機能を追加する際に、Firestoreのスキーマを変える必要が出てきました。やりたいことは、
「 今までのデータを読み取って、別の形式に再構成する 」
という感じのことで、止めないとダメかなと。メンテンナンスのときの手順
手順はこんな感じ。
- メンテナンス画面に遷移するようにmiddlewareを変更
- firestoreのルールを全部ブロックするように変更
- スキーマ変更処理を実行
- メンテナンス画面を解除し、hostingに最新版をアップロード
- firestoreのルールをもとに戻す
ポイントとしては、
- ページを移動したら、middlewareでメンテナンス画面に遷移する
- クライアントから変更されないように、全部ブロックするルールに変更する
の2点くらい。
結果、かなりの失敗をしました。。
やらかした失敗と反省点
ダメだったのは以下の2点。
- 時間がかかりすぎ(予想5h以内→実際11h)
- メンテナンス画面がちゃんと出ていなかった
1. 時間がかかりすぎ問題
一番の失敗は時間かかりすぎです。。
予想以上に時間が。。予想5h以内→実際11h対象のスキーマが、
本 - 履歴 - ユーザ多対多の関係を持つ構造を持っていて、
本を起点に履歴データの構造を変更するような処理だった。規模としては、本の件数が47670ドキュメントで、履歴が58144ドキュメント。
実際に実行してみたところ、速度が上がったり下がったりで、
1時間に5000冊位な感じ。。これだけで10時間近く。。振り返ってみて
やってみていくつか良くない感じだったなと。。
振り返ってみて、改善できそうなのは以下の2点な感じ。。a. メンテナンスでは差分部分のみ反映する
全量を読み込んで、反映していたので、かなりの時間が。。
とはいえ、1日の変更であれば、そこまで多くないので、
事前に全量の変更を用意しておき、メンテナンスにしてから、
差分があるところだけを更新をするなどのほうが良かった気がしてる。。次はそうしよう。。
b. 処理の並列実行
内部の処理も
Promise.allを使ってない部分がいくつか。。
foreachで実行している部分を置き換えて、
並列実行にするだけでも改善されそうな感じ。。この記事がわかりやすい感じだった。
- Node.js で Promise の直列実行と並列実行、同時実行数の制御 - Qiita2. メンテナンス画面が出てない
メンテナンスをはじめてから、GoogleAnalyticsを見てると、リアルタイムユーザがちらほら。
終わってからも、メンテナンス画面じゃないとの報告もちらほら。。Firebase Hostingにアップロードしてもキャッシュが残っているとだめだったもよう。。
振り返ってみて
振り返ってみて、改善できそうなのは以下の2点な感じ。。
a. PWAモジュールを使ってnetworkファーストで取得する
以下の記事の前半で書かれている通り、キャッシュ戦略を設定することで解決できそう。
・Nuxt.js(SPA)とFirebaseで強制リビジョン(バージョン)アップするならPWAモジュールを使おう - Qiitab. Remote Configを使って切り替える
同じく上記の記事で書かれている通り、Remote Configを使うのが良さそう。
・Firebase Remote Config | FirebaseRemote Configの値によって、メンテナンス画面の表示を切り替えれるようにしておけば、
Firebaseのコンソール上での変更で、切り替えれるようにできる感じ。まとめ
やってみてわかることも多いですが、なかなかつらい感じ。。
Firebase/Firestore関連の運用系の話はあまり見ないので、
とりあえず書いてみましたが、誰かの役に立てば。。こんな方法もあるよ!こっちのほうがいいよ!などあれば、
コメントもらえるとうれしいです(´ω`)ほかの失敗談
以前にもこんなのを書きました。
初級向けの話が多いですが、実際にやってみての体験談的な話。
- Nuxt.js(SPA)+Firebaseで積読用の読書管理サービスを作ってみたときにハマったこと... - Qiita
- Firebaseで作ったWebサービスを3ヶ月運用してみて、ハマったこと・知っておきたかったこと - Qiitaこんなのつくってます!!
やらかしたWebサービスはこちら。。
積読用の読書管理アプリ 『積読ハウマッチ』
積読ハウマッチは、Nuxt.js+Firebaseで開発してます!もしよかったら、遊んでみてください〜
要望・感想・アドバイスなどあれば、
公式アカウント(@MemoryLoverz)や開発者(@kira_puka)まで♪

