当ブログ人気記事!
転職体験談
Laravelで学ぶWebアプリ開発
誰でも作れるチャットアプリ
未経験への勧め

【実践Laravel】Vuetifyでツイート画面をサクッと実装する

プログラミング

HTML, CSSあんま書きたくないー!
画面手抜きしたい!
LaravelでVuetifyを使いたい!

本記事はこういった悩みに対しての記事です!


この記事を書いている僕(@Shoot58153748)は、
2020年3月現在メガベンチャーの社内スタートアップの部署で
エンジニア(1年目)をしており、

プログラミング未経験からメガベンチャーへの転職を成功させた経験・ノウハウ
Webエンジニアになってから学んだこと

をブログにまとめています。




LaravelVuetifyを使う方法に関してはこちらの記事で解説しているので参考にしてください!
※アプリの環境設定はこちらの記事を踏襲しています。


今回は
vuetifyコンポーネントの使い方に重きを置いて
ツイート画面(Vueコンポーネント)を作っていきます。

学びポイントを以下にまとめました。
是非参考にしてください!

今回のポイント

  • Vuetifyのレスポンシブレイアウト
  • Vuetifyの固定ヘッダー・フッター
  • Vuetifyの入力フォーム
  • Vuetifyのツイートカード
  • Vuetifyのモーダル画面


ツイッター風SNSアプリ作成チュートリアル
https://kumatetsublog.com/laravel-tutorial-web-application

Github
https://github.com/Shuto-san/laravel-vue-docker

スポンサーリンク

Vuetifyでツイート画面を実装

画面イメージ(現行)

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

実装(Vueコンポーネント)

最初にツイート画面(コンポーネント)の全コードを載せます!

ファイル名:resouces/js/conponents/TweetComponent.vue


ちょっと長すぎたので、こちらのGitHubのリンクで全コードを確認できます!

今回は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-rowv-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_likedtweet.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するときに少しハマったので
記事にします!




この他にもし、こんな機能を実装してほしいというリクエストがあったら
連絡ください!

実装して皆さんに共有したいと思います。


それではまた!

プログラミング
スポンサーリンク
シェアする
SHOOTをフォローする
WebエンジニアSHOOTのブログ

コメント

タイトルとURLをコピーしました