- 投稿日:2020-06-24T20:52:32+09:00
ふりかえり手法「感謝」がリモートでもできるサービスを作ってみた!
TL;DR
- Vue.js/nuxt.jsの勉強として、ふりかえり手法「感謝」を行うサービス作ったよ!
- TypeScript/CompositionAPIも使ってみたよ!
- 実際にチームのふりかえりで使ってみて、好評だったよ!やったね!
- みんなも「感謝」やろう!
経緯
業務の中でVue.js/nuxt.jsを触ろうかという話になった。
React.jsは触ったことがあったが、Vue.jsはなかったので良い機会だと思い、
まずは簡単に何か作ってみよう!ということでやってみた。
(時期的にはGW前だったので、GW中にさっと作ってみた感じです。その他追加でやってみたいことをごちゃごちゃやっていたらすごく時間かかってしまった、、、)作ったもの
以前からうっすら作ってみたいと思っていた、「感謝」というふりかえり手法をオンラインでできるサービスを作りました!
https://thanksmsg-7cb0a.web.app/唐突ですが、社内ではアジャイル開発推進みたいな立場で活動していて、その中でこの「感謝」を実施したことがありました。
その時にチームメンバー感のつながりみたいなものを強化する、すごく良いふりかえりだったことを覚えており、
リモートワークが増えた昨今でも、この「感謝」を実施できると良いんじゃないか!あと簡単に作れそうだし!という思いで作りました!
(もちろんMiroなどを使って実施することは可能ですが、「感謝」のみに特化したものはあまりないかなと思ったこともあります。その他諸々の作った理由はおいおい、、、)ふりかえり手法「感謝」とは
アジャイルレトロスペクティブ でも書かれているふりかえり手法で、チームメンバー感で仕事の中で感じた感謝の思いについて、カードなどに書いて思いを伝えることで、チームメンバー感の関係性向上であったり、チームの雰囲気を上向かせる効果があります。
スプリントのふりかえりで使用したり、ふりかえりの最後にさっとやることで、良い雰囲気でスプリントを終了することができます。
課題が多く雰囲気が暗くなっているチームでやってみると、ポジティブな気持ちを持たせたりすることができるのでおすすめです!何か節目節目のイベントでやってみるのも良いでしょう。特徴
シンプル
機能的にはシンプルで、ワークスペースID(またはURL)を共有して、感謝の言葉を入力するだけです!
「感謝」が実施できるだけなので、特別込み入った説明不要で利用できることを目指しました!導入障壁を低く
ここが作りたかった理由なのですが、社内のアジャイル開発の取り組みが途上なこともあり、
MiroやTrelloなどのツールについて、まだチームメンバーが慣れておらず、
ふりかえりなどに利用しづらいということがありました。(ユーザー認証がうまくいかない、アカウント作れない、ボードが見つからないetc...)
その経験を生かし、このサービスについてはとことん導入障壁を低く設定しました。
特定の認証機構ではなく、ワークスペースIDの共有という形で実現することで、アジャイル開発に慣れていないチームでも簡単に利用することができます。Kudoカードを参考に
この「感謝」というふりかえりはManagement3.0で Kudoカード という形で形式化されています。
リモート以前はこのサイトページからpdfをダウンロードして、カードを作成して利用させていただいてました。
今回のカードデザインについてはKudoカードを参考に実装してみました!技術スタック
- Vue.js
- nuxt.js
- TypeScript
- CompositionAPI
- Firestore
- MVP.css
Vue.js/nuxt.jsを勉強しながら短期間で作れるかな〜という挑戦でしたが、
簡単なチュートリアルサイトをこなすだけで基礎実装部分は比較的容易に実装できました!
これまでReact.jsしか触ったことがなかったので、確かに導入についてはものすごく簡単にフロントエンド実装ができる印象です。
しかしながら、TypeScriptがtemplete内で補完が効かなかったり、固めに作ることについてはやはりReactの方が向いているのかな、、、という印象でした。
しかしながら、プロトタイプなど簡単にものを作ること自体は容易にできるので、うまく使い分けながらこれからも利用していきます。このサービスのソースはGitHubで公開しているので、もしオープンなところではなく自前の環境で動かしたい場合は、
Firebaseプロジェクト作って認証情報を置くだけで使えるので、そちらでもお使いいただけます!https://github.com/theMistletoe/thxmsg
実際に業務で使うことに
GWで主要な機能だけ作り、「こんなの作りました!」とチームで自慢してから数日後。。。
チームに疲れが見え、ちょうど節目のタイミングであった金曜日に、
スクラムマスターから「今日のふりかえりで『感謝』を実施します!ツールはこれです!」と言われたURLには作ったサービスのURLが!
ということで、所属するチームのふりかえりで使ってもらえました!使ってみた感想
作った側の感想
- メッセージの長さに制限がないので、文章に悩まずかけてそうだなと感じました。
- ペンで書くよりも労力が少ないので、たくさんのカードが出た気がします。
利用者側の感想
- チームの雰囲気を元気に出来た!
- 別の現場で使ってみたい!
まとめ
たくさんの感想いただけて、自分の作ってみたものが実際に使われるのは、エンジニア冥利につきますね!
ポジティブな感想をたくさんいただけたのもそうですし、自分の作ったものが実際に使われるのはものすごく嬉しかったです。今後もリモートでのチーム運営をする現場はたくさん増えてくると思います。
リモートチームではどうしてもコミュニケーションタイミングが減りがちになるので、
チームメンバーに感謝・リスペクトを表明できる「感謝」の振り返りを実施して、
活気あるチームが増えればなと思います!参考
- https://note.com/aliz/n/nda7438249ca8
- https://firebase.google.com/docs/firestore/quickstart?authuser=0
- https://firebase.google.com/docs/web/setup?authuser=0#config-object
- https://medium.com/@astatsuya/cloud-firestore%E3%81%A8vue-js%E3%81%A7%E3%83%87%E3%83%BC%E3%82%BF%E3%83%BC%E3%83%99%E3%83%BC%E3%82%B9%E9%80%9A%E4%BF%A1%E3%82%92%E8%A1%8C%E3%81%86-1195352c543f
- https://www.virment.com/save-data-to-firestore-vue-js-form/
- https://qiita.com/To-K/items/1ddaa8882e8c0b7ae280
- https://tech.moyashidaisuke.com/entry/nuxt-core-js-error
- https://qiita.com/yfujii1127/items/c77bff6f0177b4ff219e
- https://www.soudegesu.com/post/javascript/send-and-recieve-data-in-nuxt/
- 投稿日:2020-06-24T17:39:41+09:00
RailsとVueのアプリでbin/webpackできない
Vueを導入したRails6アプリでbin/webpackがエラーになったのでメモ。
これはアプリの初期段階で行ったもので、色々変わっても問題ない状況で試したことです。
なのでもう実装が進んでる方の場合は気をつけてください。bin/webpackを実行したら、
error Command "webpack" not found.というエラーが出た。
なぜかはわからないが、
yarn add webpackでwebpackをインストール。
再度bin/webpackをすると、
One CLI for webpack must be installed. --省略 Do you want to install 'webpack-cli' (yes/no):と出たので、yesでwebpack-cliをインストール。
再度bin/webpackすると、
Error: Cannot find module '@rails/webpacker'というエラー。
bin/rails webpacker:installこれでwebpackerを再度インストール。
bin/webpackで確認すると
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.というエラー。
とりあえず、Vueとwebpackerを合わせるために
rails webpacker:install:vueを実行。
再度bin/webpack
Error: vue-loader requires @vue/compiler-sfc to be present in the dependency tree.というエラー。
yarn add @vue/compiler-sfcこれを実行した後に、bin/webpackを試したら実行できた。
- 投稿日:2020-06-24T17:15:27+09:00
独学4ヶ月の初心者がポートフォリオ(SPA)を作ってみた Vue Router + Vuex + Laravel
はじめに
皆さんいつもお世話になり、ありがとうございます
今回、独学4ヶ月初心者の私がアウトプットのために、フロントにVue.js、バックにLaravelを使用して、オリジナルのSPA(シングルページアプリケーション)を作成してみました
学習の記録として投稿させていただきますので、どうぞよろしくお願い申し上げますアプリの概要
■ アプリ名 LARA_LABEL 高機能メモアプリ
1枚のラベル(ポストイット的な存在のやつ)に、メモ機能、ブックマーク機能、カラーリング機能、スニペット機能、を全て詰め込んだ、学習効率化アプリです。ラベルは、フォルダ分けして管理することができ、キーワード及びカラー検索機能で呼び出し、コピーボタンをクリックすることで、登録したコマンドやスニペットをコピペすることができます
レスポンシブにつきましては、現在学習中のため非対応です...■ アプリ作成の背景
プログラミング学習において、最も多くの時間を費やすのがググる時間だと思います。私も学習において、分からないことがある度に、ググってブックマークしたり、Qiitaで諸先輩方のありがたい教えをストックしてを繰り返しております。しかし、いざ学んだ知識を使いたいと思った時に、どのサイトに情報があったか分からなくなったり、Qiitaにストックした記事を見つけるのに時間がかかったりと、無駄な時間を使ってしまった経験がありますそこで、コマンドやスニペットをストックし、即時呼び出しを可能にすれば、時間を短縮できると考えました。さらに、その情報に紐づけてQiitaの記事やWebサイトを登録することで、効率よく管理ができるようになると思い、本アプリを作成いたしましたバージョン
■フロント
Vue.js 2.6.11
Vue Router 3.1.6
Vuex 3.3.0
Vuetify 2.2.27
Vue Meta 2.3.3■バック
PHP 7.3.17
Laravel 7.10.3■データベース
MySQL 5.7■Webサーバー
Nginx 1.17.10
php-fpm 7.3.17■環境
Docker (Laradock)
AWS EC2 (Ubuntu 18.04)機能一覧
■ユーザー情報関連
・新規ユーザー登録
・ログイン・ログアウト
・ソーシャルログイン (Google, GitHub, Facebook)
・簡単ログイン
・アカウント削除■メイン機能
・フォルダ 一覧表示、作成、編集、削除
・ラベル 一覧表示、作成、編集、削除
・キーワード検索
・カラー検索
・ページネーション
・ドラックアンドドロップによる並び替え
・背景画像変更アプリ紹介
■ユーザー登録 / ログイン
Vue Routerを使用して、ログインページコンポーネントにルーティングを行いました。
ユーザー認証情報はaxiosでLaravelと非同期通信を行い、Vuexのストアで管理しております。
クッキーからトークンを取り出し、HTTPヘッダーに含めてリクエスト送信することでCSRF対策を行っております。
Socialiteを使って、SNSログインを実装しました。右のラベルイメージをクリックすることで、ゲストユーザーとして簡単ログインが可能です■フォルダ
ユーザーはフォルダを作成、編集、削除することができます。上部の検索フォームにて検索を行うことができます。フォルダのドラッグアンドドロップによる並び替えを実装したかったのですが、現在の実力では実現できませんでしたので、今後の課題としております■ラベル作成
上部ナビバーのCreate Labelボタンをクリックするとモーダルが開きます。Title、Text、Colorは必須で、URLはnull可です。Textはコピーエリアなので、頻出のコマンド等をすることで、即時呼び出しが可能になります■ラベル 一覧表示
ラベルはターミナルを切り取ってポストイットにしました風なデザインです...コピーボタンをクリックすることで、Text部分がクリップボードにコピーされます。私はDockerのコマンドやEC2のsshログインコマンドをよく忘れるので、登録してすぐ呼び出せるようにしております。ナビバーのSearch Labelエリアでキーワード検索、Search by colorエリアで色検索ができます。background-imageエリアで背景画像を変更できます。■スニペット作成
ラベルのスニペットアイコンから登録可能です。上記の例では本アプリで使用したログインコンポーネントをスニペットとして登録しております。Copyボタンクリックでクリップボードにコピーされます。Vue.jsのコンポーネントや、お気に入りのCSSをスニペットに登録して、すぐに使い回すことが可能です■タイトル&テキスト編集
タイトル及びテキストは直接編集し、エンターキーを押すことで登録が可能です■カラー編集
Edit Color ボタンで色を変更できます■URL追加及び編集
URLは後から追加できます。あらかじめ登録してある場合は編集モードに切り替わります学んだこと
・SPAの基本的な開発方法及び実装の難しさ
・Vue Router Vuexの活用方法
・クッキー認証とCSRF対策
・ソーシャルログイン機能の実装
・axiosによる非同期通信
・ローカル開発から本番環境デプロイまでの基本的な流れおわりに
今回は、初めてオリジナルのアプリをゼロから作成し、デプロイまでやってみました。1つ機能を実装する度にエラーに遭遇し、何度も心が折れそうになりながら、とりあえず形にすることができました実際にアプリを作ってみて、自分の実力の無さを改めて実感しました今後もVue.jsとLaravelを使ってどんどんアプリを作り、成長できるよう努力を続けていきたいです
引き続きどうぞよろしくお願い申し上げますMahalo
takunosuke
- 投稿日:2020-06-24T17:15:27+09:00
独学4ヶ月の初心者がSPA(シングルページアプリケーション)を作ってみた Vue Router + Vuex + Laravel
はじめに
皆さんいつもお世話になり、ありがとうございます
今回、独学4ヶ月初心者の私がアウトプットのために、フロントにVue.js、バックにLaravelを使用して、オリジナルのSPA(シングルページアプリケーション)を作成してみました
学習の記録として投稿させていただきますので、どうぞよろしくお願い申し上げますアプリの概要
■ アプリ名 LARA_LABEL 高機能メモアプリ
1枚のラベル(ポストイット的な存在のやつ)に、メモ機能、ブックマーク機能、カラーリング機能、スニペット機能、を全て詰め込んだ、学習効率化アプリです。ラベルは、フォルダ分けして管理することができ、キーワード及びカラー検索機能で呼び出し、コピーボタンをクリックすることで、登録したコマンドやスニペットをコピペすることができます
レスポンシブにつきましては、現在学習中のため非対応です...■ アプリ作成の背景
プログラミング学習において、最も多くの時間を費やすのがググる時間だと思います。私も学習において、分からないことがある度に、ググってブックマークしたり、Qiitaで諸先輩方のありがたい教えをストックしてを繰り返しております。しかし、いざ学んだ知識を使いたいと思った時に、どのサイトに情報があったか分からなくなったり、Qiitaにストックした記事を見つけるのに時間がかかったりと、無駄な時間を使ってしまった経験がありますそこで、コマンドやスニペットをストックし、即時呼び出しを可能にすれば、時間を短縮できると考えました。さらに、その情報に紐づけてQiitaの記事やWebサイトを登録することで、効率よく管理ができるようになると思い、本アプリを作成いたしましたバージョン
■フロント
Vue.js 2.6.11
Vue Router 3.1.6
Vuex 3.3.0
Vuetify 2.2.27
Vue Meta 2.3.3■バック
PHP 7.3.17
Laravel 7.10.3■データベース
MySQL 5.7■Webサーバー
Nginx 1.17.10
php-fpm 7.3.17■環境
Docker (Laradock)
AWS EC2 (Ubuntu 18.04)機能一覧
■ユーザー情報関連
・新規ユーザー登録
・ログイン・ログアウト
・ソーシャルログイン (Google, GitHub, Facebook)
・簡単ログイン
・アカウント削除■メイン機能
・フォルダ 一覧表示、作成、編集、削除
・ラベル 一覧表示、作成、編集、削除
・キーワード検索
・カラー検索
・ページネーション
・ドラックアンドドロップによる並び替え
・背景画像変更アプリ紹介
■ユーザー登録 / ログイン
Vue Routerを使用して、ログインページコンポーネントにルーティングを行いました。
ユーザー認証情報はaxiosでLaravelと非同期通信を行い、Vuexのストアで管理しております。
クッキーからトークンを取り出し、HTTPヘッダーに含めてリクエスト送信することでCSRF対策を行っております。
Socialiteを使って、SNSログインを実装しました。右のラベルイメージをクリックすることで、ゲストユーザーとして簡単ログインが可能です■フォルダ
ユーザーはフォルダを作成、編集、削除することができます。上部の検索フォームにて検索を行うことができます。フォルダのドラッグアンドドロップによる並び替えを実装したかったのですが、現在の実力では実現できませんでしたので、今後の課題としております■ラベル作成
上部ナビバーのCreate Labelボタンをクリックするとモーダルが開きます。Title、Text、Colorは必須で、URLはnull可です。Textはコピーエリアなので、頻出のコマンド等をすることで、即時呼び出しが可能になります■ラベル 一覧表示
ラベルはターミナルを切り取ってポストイットにしました風なデザインです...コピーボタンをクリックすることで、Text部分がクリップボードにコピーされます。私はDockerのコマンドやEC2のsshログインコマンドをよく忘れるので、登録してすぐ呼び出せるようにしております。ナビバーのSearch Labelエリアでキーワード検索、Search by colorエリアで色検索ができます。background-imageエリアで背景画像を変更できます。■スニペット作成
ラベルのスニペットアイコンから登録可能です。上記の例では本アプリで使用したログインコンポーネントをスニペットとして登録しております。Copyボタンクリックでクリップボードにコピーされます。Vue.jsのコンポーネントや、お気に入りのCSSをスニペットに登録して、すぐに使い回すことが可能です■タイトル&テキスト編集
タイトル及びテキストは直接編集し、エンターキーを押すことで登録が可能です■カラー編集
Edit Color ボタンで色を変更できます■URL追加及び編集
URLは後から追加できます。あらかじめ登録してある場合は編集モードに切り替わります学んだこと
・SPAの基本的な開発方法及び実装の難しさ
・Vue Router Vuexの活用方法
・クッキー認証とCSRF対策
・ソーシャルログイン機能の実装
・axiosによる非同期通信
・ローカル開発から本番環境デプロイまでの基本的な流れおわりに
今回は、初めてオリジナルのアプリをゼロから作成し、デプロイまでやってみました。1つ機能を実装する度にエラーに遭遇し、何度も心が折れそうになりながら、とりあえず形にすることができました実際にアプリを作ってみて、自分の実力の無さを改めて実感しました今後もVue.jsとLaravelを使ってどんどんアプリを作り、成長できるよう努力を続けていきたいです
引き続きどうぞよろしくお願い申し上げますMahalo
takunosuke
- 投稿日:2020-06-24T17:15:27+09:00
独学4ヶ月の初心者がシングルページアプリケーションを作ってみた Vue.js + Vue Router + Vuex + Laravel
はじめに
皆さんいつもお世話になり、ありがとうございます
今回、アウトプットのために、フロントにVue.js、バックにLaravelを使用して、オリジナルのシングルページアプリケーションを作成してみました
学習の記録として投稿させていただきますので、どうぞよろしくお願い申し上げますアプリの概要
■ アプリ名 LARA_LABEL 高機能メモアプリ
1枚のラベル(ポストイット的な存在のやつ)に、メモ機能、ブックマーク機能、カラーリング機能、スニペット機能、を全て詰め込んだ、学習効率化アプリです。ラベルは、フォルダ分けして管理することができ、キーワード及びカラー検索機能で呼び出し、コピーボタンをクリックすることで、登録したコマンドやスニペットをコピペすることができます
レスポンシブにつきましては、現在学習中のため非対応です...■ アプリ作成の背景
プログラミング学習において、最も多くの時間を費やすのがググる時間だと思います。私も学習において、分からないことがある度に、ググってブックマークしたり、Qiitaで諸先輩方のありがたい教えをストックしてを繰り返しております。しかし、いざ学んだ知識を使いたいと思った時に、どのサイトに情報があったか分からなくなったり、Qiitaにストックした記事を見つけるのに時間がかかったりと、無駄な時間を使ってしまった経験がありますそこで、コマンドやスニペットをストックし、即時呼び出しを可能にすれば、時間を短縮できると考えました。さらに、その情報に紐づけてQiitaの記事やWebサイトを登録することで、効率よく管理ができるようになると思い、本アプリを作成いたしましたバージョン
■フロント
Vue.js 2.6.11
Vue Router 3.1.6
Vuex 3.3.0
Vuetify 2.2.27
Vue Meta 2.3.3■バック
PHP 7.3.17
Laravel 7.10.3■データベース
MySQL 5.7■Webサーバー
Nginx 1.17.10
php-fpm 7.3.17■環境
Docker (Laradock)
AWS EC2 (Ubuntu 18.04)機能一覧
■ユーザー情報関連
・新規ユーザー登録
・ログイン・ログアウト
・ソーシャルログイン (Google, GitHub, Facebook)
・簡単ログイン
・アカウント削除■メイン機能
・フォルダ 一覧表示、作成、編集、削除
・ラベル 一覧表示、作成、編集、削除
・キーワード検索
・カラー検索
・ページネーション
・ドラックアンドドロップによる並び替え
・背景画像変更アプリ紹介
■ユーザー登録 / ログイン
Vue Routerを使用して、ログインページコンポーネントにルーティングを行いました。
ユーザー認証情報はaxiosでLaravelと非同期通信を行い、Vuexのストアで管理しております。
クッキーからトークンを取り出し、HTTPヘッダーに含めてリクエスト送信することでCSRF対策を行っております。
Socialiteを使って、SNSログインを実装しました。右のラベルイメージをクリックすることで、ゲストユーザーとして簡単ログインが可能です■フォルダ
ユーザーはフォルダを作成、編集、削除することができます。上部の検索フォームにて検索を行うことができます。フォルダのドラッグアンドドロップによる並び替えを実装したかったのですが、現在の実力では実現できませんでしたので、今後の課題としております■ラベル作成
上部ナビバーのCreate Labelボタンをクリックするとモーダルが開きます。Title、Text、Colorは必須で、URLはnull可です。Textはコピーエリアなので、頻出のコマンド等をすることで、即時呼び出しが可能になります■ラベル 一覧表示
ラベルはターミナルを切り取ってポストイットにしました風なデザインです...コピーボタンをクリックすることで、Text部分がクリップボードにコピーされます。私はDockerのコマンドやEC2のsshログインコマンドをよく忘れるので、登録してすぐ呼び出せるようにしております。ナビバーのSearch Labelエリアでキーワード検索、Search by colorエリアで色検索ができます。background-imageエリアで背景画像を変更できます。■スニペット作成
ラベルのスニペットアイコンから登録可能です。上記の例では本アプリで使用したログインコンポーネントをスニペットとして登録しております。Copyボタンクリックでクリップボードにコピーされます。Vue.jsのコンポーネントや、お気に入りのCSSをスニペットに登録して、すぐに使い回すことが可能です■タイトル&テキスト編集
タイトル及びテキストは直接編集し、エンターキーを押すことで登録が可能です■カラー編集
Edit Color ボタンで色を変更できます■URL追加及び編集
URLは後から追加できます。あらかじめ登録してある場合は編集モードに切り替わります学んだこと
・SPAの基本的な開発方法及び実装の難しさ
・Vue Router Vuexの活用方法
・クッキー認証とCSRF対策
・ソーシャルログイン機能の実装
・axiosによる非同期通信
・ローカル開発から本番環境デプロイまでの基本的な流れおわりに
今回は、初めてオリジナルのアプリをゼロから作成し、デプロイまでやってみました。1つ機能を実装する度にエラーに遭遇し、何度も心が折れそうになりながら、とりあえず形にすることができました実際にアプリを作ってみて、自分の実力の無さを改めて実感しました今後もVue.jsとLaravelを使ってどんどんアプリを作り、成長できるよう努力を続けていきたいです
引き続きどうぞよろしくお願い申し上げますMahalo
takunosuke
- 投稿日:2020-06-24T17:15:27+09:00
独学4ヶ月の初心者がSPA(シングルページアプリケーション)を作ってみた Vue.js + Vue Router + Vuex + Laravel
はじめに
皆さんいつもお世話になり、ありがとうございます
今回、独学4ヶ月初心者の私がアウトプットのために、フロントにVue.js、バックにLaravelを使用して、オリジナルのSPA(シングルページアプリケーション)を作成してみました
学習の記録として投稿させていただきますので、どうぞよろしくお願い申し上げますアプリの概要
■ アプリ名 LARA_LABEL 高機能メモアプリ
1枚のラベル(ポストイット的な存在のやつ)に、メモ機能、ブックマーク機能、カラーリング機能、スニペット機能、を全て詰め込んだ、学習効率化アプリです。ラベルは、フォルダ分けして管理することができ、キーワード及びカラー検索機能で呼び出し、コピーボタンをクリックすることで、登録したコマンドやスニペットをコピペすることができます
レスポンシブにつきましては、現在学習中のため非対応です...■ アプリ作成の背景
プログラミング学習において、最も多くの時間を費やすのがググる時間だと思います。私も学習において、分からないことがある度に、ググってブックマークしたり、Qiitaで諸先輩方のありがたい教えをストックしてを繰り返しております。しかし、いざ学んだ知識を使いたいと思った時に、どのサイトに情報があったか分からなくなったり、Qiitaにストックした記事を見つけるのに時間がかかったりと、無駄な時間を使ってしまった経験がありますそこで、コマンドやスニペットをストックし、即時呼び出しを可能にすれば、時間を短縮できると考えました。さらに、その情報に紐づけてQiitaの記事やWebサイトを登録することで、効率よく管理ができるようになると思い、本アプリを作成いたしましたバージョン
■フロント
Vue.js 2.6.11
Vue Router 3.1.6
Vuex 3.3.0
Vuetify 2.2.27
Vue Meta 2.3.3■バック
PHP 7.3.17
Laravel 7.10.3■データベース
MySQL 5.7■Webサーバー
Nginx 1.17.10
php-fpm 7.3.17■環境
Docker (Laradock)
AWS EC2 (Ubuntu 18.04)機能一覧
■ユーザー情報関連
・新規ユーザー登録
・ログイン・ログアウト
・ソーシャルログイン (Google, GitHub, Facebook)
・簡単ログイン
・アカウント削除■メイン機能
・フォルダ 一覧表示、作成、編集、削除
・ラベル 一覧表示、作成、編集、削除
・キーワード検索
・カラー検索
・ページネーション
・ドラックアンドドロップによる並び替え
・背景画像変更アプリ紹介
■ユーザー登録 / ログイン
Vue Routerを使用して、ログインページコンポーネントにルーティングを行いました。
ユーザー認証情報はaxiosでLaravelと非同期通信を行い、Vuexのストアで管理しております。
クッキーからトークンを取り出し、HTTPヘッダーに含めてリクエスト送信することでCSRF対策を行っております。
Socialiteを使って、SNSログインを実装しました。右のラベルイメージをクリックすることで、ゲストユーザーとして簡単ログインが可能です■フォルダ
ユーザーはフォルダを作成、編集、削除することができます。上部の検索フォームにて検索を行うことができます。フォルダのドラッグアンドドロップによる並び替えを実装したかったのですが、現在の実力では実現できませんでしたので、今後の課題としております■ラベル作成
上部ナビバーのCreate Labelボタンをクリックするとモーダルが開きます。Title、Text、Colorは必須で、URLはnull可です。Textはコピーエリアなので、頻出のコマンド等をすることで、即時呼び出しが可能になります■ラベル 一覧表示
ラベルはターミナルを切り取ってポストイットにしました風なデザインです...コピーボタンをクリックすることで、Text部分がクリップボードにコピーされます。私はDockerのコマンドやEC2のsshログインコマンドをよく忘れるので、登録してすぐ呼び出せるようにしております。ナビバーのSearch Labelエリアでキーワード検索、Search by colorエリアで色検索ができます。background-imageエリアで背景画像を変更できます。■スニペット作成
ラベルのスニペットアイコンから登録可能です。上記の例では本アプリで使用したログインコンポーネントをスニペットとして登録しております。Copyボタンクリックでクリップボードにコピーされます。Vue.jsのコンポーネントや、お気に入りのCSSをスニペットに登録して、すぐに使い回すことが可能です■タイトル&テキスト編集
タイトル及びテキストは直接編集し、エンターキーを押すことで登録が可能です■カラー編集
Edit Color ボタンで色を変更できます■URL追加及び編集
URLは後から追加できます。あらかじめ登録してある場合は編集モードに切り替わります学んだこと
・SPAの基本的な開発方法及び実装の難しさ
・Vue Router Vuexの活用方法
・クッキー認証とCSRF対策
・ソーシャルログイン機能の実装
・axiosによる非同期通信
・ローカル開発から本番環境デプロイまでの基本的な流れおわりに
今回は、初めてオリジナルのアプリをゼロから作成し、デプロイまでやってみました。1つ機能を実装する度にエラーに遭遇し、何度も心が折れそうになりながら、とりあえず形にすることができました実際にアプリを作ってみて、自分の実力の無さを改めて実感しました今後もVue.jsとLaravelを使ってどんどんアプリを作り、成長できるよう努力を続けていきたいです
引き続きどうぞよろしくお願い申し上げますMahalo
takunosuke
- 投稿日:2020-06-24T15:21:41+09:00
【Vue】学習開始3週目で覚える内容
3週目で学ぶべきこと
- 双方向データバインディング
- 修飾子
コンポーネント間バインディング
- 入力値を
$event.target.value
で受け取るprops
,$emit
を使用してデータバインディングを行う◆ 親コンポーネント
App.vue<template> <!-- v-modelで入力された値を"Child.vue"に"$event"として共有する --> <Child v-model="sample"></Child> </template> <script> export default { data() { return { //sample:属性名 YES:初期値 sample: "YES" } } }; </script>◆ 子コンポーネント
Child.vue<template> <!-- "親コンポーネントのv-model"で入力された値を受け取る --> <input :value="value" @input="$emit('input', $event.target.value)" > <!-- "子コンポーネントの入力値を"$emit"を使用して、"親コンポーネント"と共有する --> <!-- input:属性値 $event.target.value:入力値 --> </template> <script> export default { //"親コンポーネント"の"v-model"入力値 props: ["value"] } <script>テキストボックスバインディング
p style="white-space: pre-line;"
を使って、空白・改行を反映するtextareaタグ
+v-model
でテキストボックスを作成するplaceholder
は、入力欄の初期値
を指定するApp.vue<template> <div> <!-- "textarea" + "v-model"で、入力欄作成 --> <textarea v-model="sample" placeholder="入力欄"></textarea> <!-- p style="white-space: pre-line;"で空白・改行を反映する --> <p style="white-space: pre-line;">{{ sample }}</p> </div> </template> <script> export default { data() { return { //sample:属性名 sample: "" } } }; </script>単体チェックボックスバインディング
input type="checkbox"
で、チェックボックス作成- v-modelで指定するプロパティは、
string or numberを選択するboolean型
App.vue<template> <div> <!-- "checkbox"をセットする --> <input type="checkbox" id="sample" v-model="sample"> </div> </template> <script> export default { data() { return { //string or numberを選択するboolean型 sample: false } } }; </script>複数チェックボックスバインディング
- labelタグ:
label forの属性値
と、inputタグのid属性値
が同じ場合、紐付けられる- 複数選択のチェックボックスの場合、dataプロパティ値(sample)は、
配列
をセットするApp.vue<template> <div> <!-- "YES"を選ぶcheckboxをセットする --> <input type="checkbox" id="1" value="YES" v-model="sample"> <label for="1">YES</label> <!-- "NO"を選ぶcheckboxをセットする --> <input type="checkbox" id="1" value="NO" v-model="sample"> <label for="1">NO</label> <!-- "checkboxで選択した値"を出力する --> <p>{{sample}}</p> </div> </template> <script> export default { data() { return { //checkboxで選択した値を"配列"として受け取る sample: [] } } }; </script>ラジオボタンバインディング
inputタグのid属性値
とlabel for
の属性値は同じ値
をセットすることで紐付けるinput type="radio"
でラジオボタン
を作成する- 各々の選択肢に
同じv-model
を設定することで、選択可能になるApp.vue<template> <div> <!-- "YES"を選択するラジオボタンをセットする --> <input type="radio" id="1" value="YES" v-model="sample"> <label for="1">YES</label> <!-- "NO"を選択するラジオボタンをセットする --> <input type="radio" id="2" value="NO" v-model="sample"> <label for="2">NO</label> </div> </template> <script> export default { data() { return { //sample:属性名 YES:初期値 sample: "YES" } } }; </script>セレクトボックスバインディング
v-for="引数 in 配列"
でレンダリングを実施するmultiple
は複数選択
を許容するApp.vue<template> <div> <!-- セレクトボックスの入力値とdataプロパティ属性値を"v-model"で関連付ける --> <!-- "multiple"は、複数選択を許可する --> <select v-model="sample" multiple> <!-- v-forディレクティブで"リストレンダリング"を実施し、keyに"sample"をセットする --> <option v-for="sample in samples" :key="sample">{{sample}}</option> </select> <!-- セレクトボックスで選択した内容を出力する --> <p>{{sample}}</p> </div> </template> <script> export default { data() { return { //v-forディレクティブで使用する"配列"を作成する samples: ["犬", "ネコ", "ウサギ"], //セレクトボックスの"初期値"を設定する sample: "犬" } } }; </script>修飾子
◆ lazy修飾子
changeイベント
後に、データを反映させる
- デフォルトでは、v-modelは
inputイベント
後に反映させるApp.vue<template> <div> <!-- lazy修飾子によって、"changeイベント"後にデータ反映 --> <input v-model.lazy="sample"> </div> </template>◆ number修飾子
- ユーザの入力を
number型
に自動変換させるApp.vue<template> <div> <!-- number修飾子によって、入力データを"number型"に変換 --> <input v-model.number="sample" type="number"> </div> </template>◆ trim修飾子
- ユーザの入力から
空白を自動でカット
する<pre>タグ
は空白や改行をそのまま表示するApp.vue<template> <div> <!-- trim修飾子によって、入力データの空白を自動でカットする --> <input v-model.trim="sample" type="text"> <!-- "preタグ"によって、trim修飾子の"空白カット"をそのまま表示する --> <pre>{{ sample }}</pre> </div> </template> <script> export default { data() { return { //sample:属性名 default:値 sample: "default" } } }; </script>同シリーズ
参考文献
- 投稿日:2020-06-24T12:26:50+09:00
Vuetifyでテキストとボタンを横に並べる
実現したいこと
Vuetifyでテキストボックスとボタンを横並びにしたい。
ちょっと実現したいデザインは違うけど、フォームの構成としては、以下の検索窓のような感じです。テキストボックスに入力後、ルーペアイコンのボタンをクリックして検索するというパターンです。
実現方法
入力欄に使用する
v-text-field
のappend
スロットを使うと実現できました。
vuetifyの公式ドキュメントでは、Icon slotsとして紹介されています。スロットの
append-outer
を使って、以下のようにフォームを作成します。<v-text-field v-model="message" label="Message" type="text" > <template v-slot:append-outer> <v-btn color="primary">検索</v-bt> </template> </v-text-field>こんな感じになります。
codepenでサンプルを作成しました。
こちらは、スロットのappend
も記述して、append-outer
と比較しています。冒頭の検索窓のように、テキストの中にボタンがあるパターンですと、
append
スロットを指定する方が合います。テキストとボタンを並べる場合は、append-outer
がよいですね。See the Pen Vuetify Example Pen by Shigehiro IDANI (@1da2) on CodePen.
まとめ
公式ドキュメントのコンポーネントを眺めていても、組み合わせ方とかは、ある程度の経験が必要になってきます。
このタイプも、知っていれば簡単なのですが、知らないと、ズバリが見つけられなくて時間がかかるパターンでした。
- 投稿日:2020-06-24T11:27:58+09:00
タグフォーム「Voerro Vue Tags Input v2」にタグ追加ボタンをつけた
簡単にタグフォームを設置できる「Voerro Vue Tags Input v2」、
ボタンをクリックでもタグの追加 が出来るようにしました。前提:用意されたタグ追加タイミングはキー入力のみ
「Voerro Vue Tags Input v2」で用意されているタグの追加タイミングは以下
1. Enterキー押下
2. カンマ(,)入力https://github.com/voerro/vue-tagsinput/blob/master/dist/voerro-vue-tagsinput.js
https://github.com/voerro/vue-tagsinput/blob/master/src/VoerroTagsInput.vue方法:タグ追加時に実行される関数を使用
タグ追加時に実行される関数
tagFromInput();
を使用ます。<input type="button" name="" value="追加" @click="addTag"></button>addTag: function() { // voerro-vue-tagsinput.jsでタグ追加時に実行される関数 this.$refs.tagsInput.tagFromInput(); },その他「Voerro Vue Tags Input v2」組み込みに参考にしたリンク
組み込み方
https://www.kabanoki.net/5059/機能カスタマイズ
https://voerro.github.io/vue-tagsinput/リポジトリ
https://github.com/voerro/vue-tagsinput?ref=kabanoki.net
- 投稿日:2020-06-24T06:23:23+09:00
Vuex の初級編 Vue CLI版 #Vue.js #vuex
概要
Vuex の初級編的な内容で
Vue CLI で実装例となります。・ components間で、prop等で
値を受け渡した時に。反映できない場合がありましたので
vuexに、変更してみました。
参考のコード
https://github.com/kuc-arc-f/vuex_sample_1
構成
Vue CLI
vuex : 3.4.0
vue: 2.6.11参考
https://qiita.com/okumurakengo/items/0521049e79f927632cab
vuex 追加
npm install vuex --savepackage.json
https://github.com/kuc-arc-f/vuex_sample_1/blob/master/package.json
実装など
getters, mutations を定義しています。
・store.js
https://github.com/kuc-arc-f/vuex_sample_1/blob/master/src/store.jsimport Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) // export default new Vuex.Store({ state: { products: [ { id: 1, name: "Hoge", stock: 0 }, { id: 2, name: "Fuga", stock: 3 }, { id: 3, name: "Piyo", stock: 0 }, ], tasks:[], count: 5, }, getters: { depletedProducts: state => { return state.products }, getTasks: state => { return state.tasks } }, mutations: { increment(state) { state.count++ }, setTasks(state, payload) { state.tasks = payload.tasks } }, })・main.js
store を、読み込んでいますimport Vue from 'vue' import router from './router' import App from './App.vue' import store from './store' Vue.config.productionTip = false // new Vue({ store, router, render: h => h(App), }).$mount('#app')components
・読込、computed で、getters からstore.js
で、設定した。固定値を取得
・this.$store.getters.定義した取得関数で、読めるので
importなして。グローバル参照が可能でしたTestVuex.vue
https://github.com/kuc-arc-f/vuex_sample_1/blob/master/src/components/TestVuex.vueexport default { created(){ console.log( "count =" + this.$store.state.count ) }, computed: { depletedProducts() { return this.$store.getters.depletedProducts; } }, methods: { updateCount() { this.$store.commit("increment"); } } }・表示の部分
<div> <h1>TestVuex.vue</h1> Test-1: <p>Count: {{ $store.state.count }}</p> <button @click="updateCount">increment</button> <hr /> depletedProducts: <ul> <li v-for="(product, i) in depletedProducts" :key="i"> name: {{ product.name }} , ID : {{ product.id }} </li> </ul> </div>親/子 components で、読み書きする場合
・親、TestVuex_2.vue
https://github.com/kuc-arc-f/vuex_sample_1/blob/master/src/components/TestVuex_2.vuemutations で、commit( this.$store.commit('setTasks', {'tasks' : items } ) )
import {Mixin} from '../mixin' import TestChild from '../components/Element/TestChild' // export default { mixins:[Mixin], components: { TestChild }, created(){ console.log( "count =" + this.$store.state.count ) this.updateTask() // console.log( this.getTasks ) }, methods: { updateCount() { this.$store.commit("increment"); }, updateTask() { var items = [ { 'id' : 1, 'name' : 'n1'}, { 'id' : 2 , 'name' : 'n2'}, { 'id' : 3 , 'name' : 'n3'}, ] this.$store.commit('setTasks', {'tasks' : items } ) }, } }・子、TestChild.vue
https://github.com/kuc-arc-f/vuex_sample_1/blob/master/src/components/Element/TestChild.vuecomputed , getters で、読み込み ( this.$store.getters.getTasks; )
import {Mixin} from '../../mixin' // export default { mixins:[Mixin], created () { // console.log( "uid=" + this.user_id ) }, computed: { getTasks(){ return this.$store.getters.getTasks; } }, methods: { } }
- 投稿日:2020-06-24T04:40:56+09:00
【感想】Vue.js & FirebaseでTwitterライクなSNSアプリを作ろう
はじめに
今回、私が学習に使用した教材はこちらです。教材提供サイトはこちらTechpitです。
※有料です。
開発環境
Vue.js
Node.js
Firebase
今回作ったもの
感想
- Googleアカウントでのサインイン
- 投稿の新規作成、リスト表示、更新、削除です。
上記の2点が機能として今回この教材で実装でき、それらについて学ぶことが出来ます。
要するにCRUDの実装とGoogleアカウントを用いたユーザー登録ですね。個人的にはこういう個人開発に近しいものを「いざ作ろう!」となっても開発するのってすごくハードルが高いと思っていて、このようなアプリが教材形式で学ぶことが出来るのは最近始めた初学者の方や今回だとフロント周りを軽くしか触っていない自分とかにはハードルが下がってとても良いと思うんですよね。
開発の流れやこの機能を実装するにはどうしたらいいだろう?とか考えたり、その教材で使用する技術について勉強になりますし良いことしかないと思います。
正直な話自分がプログラミングを勉強し始めた時ぐらいにこういう教材などがあって気軽に学べてデプロイまでできるような環境があったらもっとフロント周りをゴリゴリやって開発していた気がします。(笑)
今からでも全然遅くないとは思っていますが。(笑)
教材を作って頂いた製作者の方やこのサイトを運営されてる方に見られるか分かりませんが、このような環境と教材を提供していただいて感謝しています。
最後に
自分は普段はインフラ・クラウド・セキュリティの方面を主に勉強していてフロント周りは軽く触ったことがあるくらいだったのですが、特に問題もなく教材通りに学びながら1日かからずにデプロイまで出来ました。(普通は時間をかけてゆっくりやるものだと思いますが、自分はサクサクやっていたのであまり参考にはならないかもしれません。)
今後もTechpitで学んだことを感想としてアウトプットしたり、自分が普段やってる方面のことなどをアウトプットしていきたいと思っています。
暇な時に流し読みでも記事を読んでいただけたらと思っています。(笑)
- 投稿日:2020-06-24T03:36:29+09:00
【Vue/Nuxt】mobile時とdesktop時でComponentを出し分けした(JSX)
mobile時とdesktop時にレスポンシブ対応するにあたって、CSSで頑張るの嫌だったのでmobile時とdesktop時でファイルを分けることにしました。
なので、備忘録がてらソースコードを貼り付けようと思っています。
その前にディレクトリの階層を貼り付けます。
ディレクトリ構造
container(ロジック)とpresenter(UI)を分けました。
また、ComponentはAtomic Designにしてます。(完璧それをやってるワケじゃないけど)
containerロジックを書いておいて、mobileとdesktop共通で使いまわせるのが地味に使い勝手よかったです。
tabletみたいなディレクトリも切って良さそうかなと思いました。
components ┗ templates ┗ ArticleDetail ┣ container.js ┣ mobile ┃ ┗ presenter.vue ┗ desktop ┗ presenter.vueソースコード
記事詳細ページ的なノリです。
JSXを利用しました。(もうなんかこっちのシンタックスの方が僕的に好きです。)
import { mapGetters } from 'vuex' import ArticleDetailMobile from '@/components/templates/ArticleDetail/mobile/presenter' import ArticleDetailDesktop from '@/components/templates/ArticleDetail/desktop/presenter' export default { name: 'ArticleDetailContainer', computed: { ...mapGetters({ articleDetail: 'article/ArticleDetail', }), }, render(h) { return this.$device.isMobile ? h(ArticleDetailMobile, { props: { articleDetail: this.articleDetail, }, }) : h(ArticleDetailDesktop, { props: { articleDetail: this.articleDetail, }, }) }, }