
HTML, CSSあんま書きたくないー!
画面手抜きしたい!
LaravelでVuetifyを使いたい!
本記事はこういった悩みに対しての記事です!
この記事を書いている僕は、
2020年3月現在メガベンチャーの社内スタートアップの部署で
エンジニア(1年目)をしており、
プログラミング未経験からメガベンチャーへの転職を成功させた経験・ノウハウ
Webエンジニアになってから学んだこと
をブログにまとめています。LaravelでVuetifyを使う方法に関してはこちらの記事で解説しているので参考にしてください!
※アプリの環境設定はこちらの記事を踏襲しています。
今回はvuetifyコンポーネントの使い方に重きを置いて
ツイート画面(Vueコンポーネント)を作っていきます。
学びポイントを以下にまとめました。
是非参考にしてください!
今回のポイント
- Vuetifyのレスポンシブレイアウト
- Vuetifyの固定ヘッダー・フッター
- Vuetifyの入力フォーム
- Vuetifyのツイートカード
- Vuetifyのモーダル画面
ツイッター風SNSアプリ作成チュートリアル
https://kumatetsublog.com/laravel-tutorial-web-application
目次
Vuetifyでツイート画面を実装
画面イメージ(現行)

画面イメージ(Vuetify導入後)

実装(Vueコンポーネント)
すみませんコード見たい方は連絡ください。
ファイル名:resouces/js/conponents/TweetComponent.vue
今回は5つのポイントに絞って解説していきます!
レスポンシブ対応
基本的に、v-row(行)の中に、v-col(列)を配置し、レイアウト(グリッド)を整えます!<v-row align="center" justify="center">
align(縦方向)、 justify(横方向)で中の要素の配置を指定<v-col cols="12" sm="8" md="4">
でレスポンシブ対応を記述します。
ポイントは、幅は12で100%横幅が埋まります。
ざっくり、cols:スマホサイズ、sm:タブレットサイズ、md:ラップトップサイズ
の時の横幅サイズを指定することができます。
今回の場合、
スマホで見た場合、横幅いっぱいに表示されるが、
パソコンで見ると、全体の1/3ほどの大きさで表示されます。vuetifyを使いこなす上でv-rowとv-colは欠かせないものなので、
是非とも使い方をマスターしましょう!
固定ヘッダー
<v-app-bar>にいくつかパラメーターを加えてあげます。height="auto":ヘッダーの高さを自動にして、中のフォームの大きさに合わせるfixed:ヘッダーを上部に固定
これだけで上部の固定部分が実現できます。
<v-app-bar
color="white"
height="auto"
fixed>
<v-row
align="center"
justify="center"
>
<v-col
cols="12"
sm="8"
md="4"
>
<v-form
ref="form"
v-model="valid"
lazy-validation>
<v-text-field
label="Say your thoughts!"
v-model.trim="tweet"
:counter="255"
:rules="tweetRules"
required
solo
>
</v-text-field>
<v-spacer />
<v-btn
color="primary mr-4"
@click="storeTweet"
:disabled="!canSubmit"
>Tweet!</v-btn>
</v-form>
</v-col>
</v-row>
</v-app-bar>
フォーム(バリデーション)
<v-form>タグでフォームのバリデーションを設定できます。lazy-validation:表示されるバリデーションエラーが無い限り、value(バリデーション)はtrue(通った状態)になる<v-text-field>で入力データを作り出します。v-model.trim:入力した文字をバインディング:counter:文字をカウントをしてくれる(XX/255):rules:バリデーションルールを設定(
tweetRules: [
v => !!v || 'Tweet is required',
v => (v && v.length <= 255) || 'Tweet must be less than 255 characters',
],
)required:入力必須v-btnはボタンですね。@click:クリックイベント発火:disable:変数canSubmitにより表示非表示制御
Ajax通信(axios)とバリデーションのJSは過去の記事で詳しく解説しているので、そちらを参考にしてください!
(下線部クリックで過去記事に遷移)
<v-form
ref="form"
v-model="valid"
lazy-validation>
<v-text-field
label="Say your thoughts!"
v-model.trim="tweet"
:counter="255"
:rules="tweetRules"
required
solo
>
</v-text-field>
<v-spacer />
<v-btn
color="primary mr-4"
@click="storeTweet"
:disabled="!canSubmit"
>Tweet!</v-btn>
</v-form>
ツイートカード
v-cardでツイッターカードを作成していきます。
中身の構成は以下な感じ(v-cardの中に以下のタグを入れると良い感じにレイアウトしてくれる)v-card-title:カードのタイトル部(ツイッターアイコンとTwitterという文字)v-card-text:カードのテキスト部v-card-action:カードの下部のボタンなどアクション要素(v-list-item-avater:アバター画像、v-list-item-content:ユーザーネーム、v-row:ハートや通報ボタンアイコン)
いいねや通報アイコンはv-iconで表現します。タグの中身をmdi-XXXXで表示するアイコンを設定
ハートアイコンをクリックするとpushLike(JS)が実行されてサーバー側にリクエストを送り、いいねデータを更新
通報アイコンをクリックするとopenModal(JS)が実行されて、通報用のモーダル画面が出てきます。
いいね済み、または通報済みかどうかは、変数tweet.is_likedとtweet.is_reportedを使ってv-ifで制御しています。
(サーバー側からそれぞれの初期状態true of falseを受け取る)
こちらもJSに関しては過去記事で解説しています。
無限スクロール
いいね機能
インプレッション機能
<v-card
class="mx-auto"
color="primary"
width="100%"
dark
>
<v-card-title>
<v-icon
small
left
>
mdi-twitter
</v-icon>
<span class="subtitle-2 font-weight-light">Twitter</span>
</v-card-title>
<v-card-text class="body-1 font-weight-bold">
"{{ tweet.tweet }}"
</v-card-text>
<v-card-actions>
<v-list-item class="grow">
<v-list-item-avatar color="grey darken-3">
<v-img
class="elevation-6"
src="https://avataaars.io/?avatarStyle=Transparent&topType=ShortHairShortCurly&accessoriesType=Prescription02&hairColor=Black&facialHairType=Blank&clotheType=Hoodie&clotheColor=White&eyeType=Default&eyebrowType=DefaultNatural&mouthType=Default&skinColor=Light"
></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>{{ tweet.nickname }}</v-list-item-title>
</v-list-item-content>
<v-row
align="center"
justify="end"
>
<v-icon v-if="tweet.is_liked" @click="pushLike(tweet)" class="mr-1" color="red" dark>mdi-heart</v-icon>
<v-icon v-else @click="pushLike(tweet)" class="mr-1">mdi-heart</v-icon>
<span class="subheading mr-2">{{ tweet.like_count }}</span>
<span class="mr-1"></span>
<v-icon v-if="tweet.is_reported" @click="openModal(tweet)" class="mr-1" color="blue" dark>mdi-flag</v-icon>
<v-icon v-else @click="openModal(tweet)" class="mr-1">mdi-flag</v-icon>
<span class="subheading"></span>
</v-row>
</v-list-item>
</v-card-actions>
</v-card>
通報モーダル画面
モーダル画面は、v-dialogで実現します。v-modelでモーダル画面の表示・非表示を制御できます。(僕のアプリでは、tweet.isDisplayという変数を用意)
中身は先ほどツイート画面を作るときに登場した、v-cardを使用
構成は同じで、上:v-card-title、中:v-card-text、下:v-card-action
ただ、v-ifを用いて通報有無でテキストを出し分けているのがポイントですね。
下部のボタンがクリックされたら、pushReport(JS)を実行し、
サーバー側にリクエストし通報データを更新します。
通報機能のJSは過去記事で詳しく解説しています。
通報機能
<v-dialog
v-model="tweet.isDisplayed"
max-width="290"
>
<v-card>
<v-card-title class="headline" v-if="tweet.is_reported">通報を取り消しますか?</v-card-title>
<v-card-title class="headline" v-else>通報しますか?</v-card-title>
<v-card-text>
※意味不明なツイート、不快なツイート、誹謗中傷を含むツイートは通報できます
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="green darken-1"
text
@click="closeModal(tweet)"
>
閉じる
</v-btn>
<v-btn
v-if="tweet.is_reported" class="btn"
color="green darken-1"
text
@click="pushReport(tweet)"
>
通報取消
</v-btn>
<v-btn
v-else
color="green darken-1"
text
@click="pushReport(tweet)"
>
通報する
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
フッター
v-bottom-navigationでボトムヘッダーを作成します。:valueでアクティブのボタン(アイコン)を設定(1,2…)fixedで下部に固定
中身はv-btnで構成しhrefでクリック後の遷移先を設定しています。
簡単ですね!
<v-bottom-navigation
:value="activeBtn"
color="primary lighten-1"
fixed
>
<v-btn href="/">
<span>Home</span>
<v-icon>mdi-home</v-icon>
</v-btn>
<v-btn href="/tweet/index">
<span>Timeline</span>
<v-icon>mdi-timeline</v-icon>
</v-btn>
</v-bottom-navigation>
まとめ
以上、Laravel×Vuetifyでツイート画面を実装しました!
個人的にもVuetify使用前、使用後の変化にびっくりです!
Vuetifyの公式ドキュメントを見ながら
1、2時間程度で実装できました。
慣れるまでは少し時間がかかるかもしれませんが、
すでにある程度の使い方の例は公式サイトに豊富にあります。
理解→組み合わせ→実装
という手順で画面を作れば、簡単にサクッと作れます!
最後に今回のポイントをまとめます。
ポイント
- Vuetifyのレスポンシブレイアウト
- Vuetifyの固定ヘッダー・フッター
- Vuetifyの入力フォーム
- Vuetifyのツイートカード
- Vuetifyのモーダル画面
あんなに華のないかつレスポンシブにも対応してなかったツイート画面がVuetifyのおかげで
おしゃれでレスポンシブ対応の画面に生まれ変わりました!
次は、
ユーザー登録画面をカスタマイズして画面系の調整は終えます!
ajax通信で登録内容をPOSTするときに少しハマったので
記事にします!
この他にもし、こんな機能を実装してほしいというリクエストがあったら
連絡ください!
実装して皆さんに共有したいと思います。
それではまた!




