search
LoginSignup
17

More than 3 years have passed since last update.

posted at

updated at

【Vuetify on Nuxt.js】実際に本番運用したコンポーネントとそのカスタマイズ

【Vuetify on Nuxt.js】実際に本番運用したコンポーネントとそのカスタマイズ

by mejileben
1 / 27

概要

本スライドはVuetify Meetup #1での発表資料です。面白そうと思った方はぜひ次回以降参加してください!LTも募集中です。


自己紹介


業務内容

Twitter @Meijin_garden
名人って呼ばれてます。

株式会社NoSchoolのCTO。
中高生のための勉強質問サイトを作ってます。
自分しかフルタイムのエンジニアがいないのでAWSもFirebaseもLaravelもNuxt.jsもデザインも採用も機械学習もやってます。


経歴

奈良高専情報工学科

株式会社LIFULL

株式会社NoSchool


Vuetify on Nuxt.jsを採用した理由


背景

2017年からNoSchoolのサイト自体はあるが、社長がWordPress on SakuraServerで起業したのでエンジニアから見たら酷いものだった。
シードの資金調達を終えて僕がジョインした2019年3月から5月にかけて、フルリプレイスを行うこととなった。


リプレイス後の技術構成

インフラ: AWS(CloudFront, ALB, EC2, S3...)
サーバーサイド: Laravel
フロントエンド: Nuxt.js, jQuery

※2ヶ月じゃフロントまで移行やりきることができず、現在もページ単位でNuxtに移行中


Nuxt.jsの採用理由

  • 僕自身がVue.jsの経験が1年強あった(前職の新規事業で1人でフルスクラッチした)
  • jQueryと比較して開発速度が段違い
  • ReactとVueだとあまり違いも採用力が衰えるということもなさそうなのでCTOの僕が経験があって開発速度がとにかく速いものを選べばいいやという考え

Vuetifyの採用理由

  • デザイナー不在でそこそこの品質で開発をするためにUIフレームワークは必須
  • Bulma、Bootstrap Vueなども見たが、Class属性ではなくコンポーネント自体を用意してくれている方が使い勝手がいいと思った
  • ちなみにElementは前職で使っていたけどレスポンシブや細かいところでイライラした

実際にVuetifyで頑張ったページたち(2019/8時点)


家庭教師一覧

スクリーンショット 2019-08-29 10.41.43.png


家庭教師詳細

スクリーンショット 2019-08-29 10.47.45.png


質問作成

FireShot Capture 001 - NoSchool - NoSchool 無料で勉強の質問、塾や家庭教師の検索 - noschool.asia.png


Vuetifyでまずこれだけ覚えておけば的なコンポーネントリスト


  • ページ(v-app, v-content等)
  • レイアウト(v-layout, v-flex
  • 余白(.py-2, .mx-4等)
  • 装飾系(v-card, v-chip, v-icon
  • 画像系(v-img, v-avatar
  • フォーム(v-btn, v-select, v-text-field等)
  • あとはドキュメントを読み込む。カスタムSlotも便利。

Vuetifyの便利コンポーネントをいくつか紹介


ページ構成(default.vue)

<template lang="pug">
v-app
  my-header
  v-content(app)
    my-breadcrumbs(:items="breadcrumbs")
    v-container(app fluid)
      nuxt
  my-footer
</template>

※ちょっと改変はしてます

v-appv-contentなどは公式ドキュメントの通り。


パンくず(Breadcrumbs.vue)

パンくずはv-breadcrumbsがベースで、カスタマイズのためにv-slot:itemを利用。

<template lang="pug">
  v-breadcrumbs(:items="items").px-2.py-0.grey.lighten-3
    template(v-slot:item="props")
      v-breadcrumbs-item(
        :to="props.item.to"
        :disabled="props.item.disabled"
        v-if="props.item.to !== '/'"
      )
        span.grey--text {{ props.item.text }}
      span(v-else)
        a(href="/").pa-0
          v-icon.body-1.primary--text mdi-{{ props.item.icon }}
    template(v-slot:divider)
      span >
</template>

↓こうなります
スクリーンショット 2019-08-29 10.58.10.png


ページネーション

<template lang="pug">
  v-pagination(
    v-model="pageModel"
    @input="onPaginationClicked"
    @next="onPaginationClicked"
    @previous="onPaginationClicked"
    :length="last_page"
    :total-visible="7"
    style="overflow-x: scroll;"
  ).my-4
</template>

scriptを抜粋するとこんな感じ。

<script>
export default {
...
  methods: {
    onPaginationClicked(event) {
      this.$emit("query-updated", {
        page: this.pageModel
      });
    }
  }
...
};
</script>

要は、ページネーションのページ番号が変わったときに呼び出し元コンポーネントで再度API叩くなりする必要があるので、親にemitする設計にしている。


ページネーションの注意

total-visibleが偶数だと、中央あたりのページ番号で表示が変になるので注意。
例えば6にしたとき、全ページ数が10などのときに5ページ目付近で表示がおかしくなり、隣り合ったページが表示されない。
これは...も含めたvisibleのcountだから、偶数だと...の数が合わなくて隣り合ったページが出ない。
(気になるなら直せやOSSだろという話ですよねすみません)


Vuetifyをベースにカスタマイズしているコンポーネント


見出し系

Vuetifyの見出しはフォントサイズが大胆なのと、サイト全体で統一感を出したいので共通コンポーネント化。

plugin/globalComponent.js
import Vue from 'vue'

import Body from "@/components/layouts/Body";
import PageTitle from "@/components/parts/heading/pageTitle";
import SubTitle from "@/components/parts/heading/subTitle";
import SubTitle2 from "@/components/parts/heading/subTitle2";

Vue.component('sec-main', Body)
Vue.component('page-title', PageTitle)
Vue.component('subtitle', SubTitle)
Vue.component('subtitle2', SubTitle2)

悩ましいのは、マージンまでコンポーネントに入れるかどうか。入れるとしたらどれくらい大きいマージンを入れるか(デザインの話になってくるけど)。


ボタン

サイトを作っていく中で、outlinedv-btnをよく使うので共通化。

<template lang="pug">
v-btn(outlined large :color="color" :to="to" @click="clicked" :block="block").py-2.mt-2
  v-icon(v-if="icon" :class="iconColor + '--text'").title.mr-2 mdi-{{ icon }}
  .subtitle-1
    slot
</template>
以下略

必須ラベル

最近作ったatoms的なのでかなり気に入ってる。

<template lang="pug">
  v-chip(small label color="accent").px-2.font-weight-bold 必須
</template>

こうなる。
スクリーンショット 2019-08-29 11.17.17.png


駆け足でしたがLTなのでこれくらいにします


最後に

NoSchoolではフロントエンドが得意で、Laravel等のサーバーサイドもゴリゴリやっていきたいWebエンジニアを募集中です!(iOSエンジニアも!
回答最適化のために機械学習も取り入れていたり、勉強意欲の強い人が自由に暴れられると思いますので是非お声がけください〜。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
17