1
0

【Nuxt3+Tailwind+PrimeVue】環境構築からダッシュボードレイアウトを組むまで

Posted at

一般的なダッシュボードレイアウトを作るよ!
コマンドは yarn を使うので適宜読み替えてください。

登場人物

Nuxt3

Vue に自動インポートやルーター機能、サーバー機能を載せた、なんでもフレームワーク。
React で言う Next。
Nuxt3 になってから、かなり綺麗に整備されており、正直 Next よりシンプルにまとまってると思う。(信者感)

Tailwind

流行りの CSS 全部 Class で書こうライブラリ。
賛否両論はあると思うが、Vue や React で採用すると、UI レイアウトを組むのが非常にはかどる。
慣れたら戻れなくなる。

PrimeVue

Vue の UI ライブラリ。
Vue と言ったら Vuetify が良く言われるが、個人的にはこちらを激押しする。
Tailwind によって組まれており、カスタマイズ、上書きがとても簡単。
ちょっと使いにくいと思うところは、気軽に上書きしていこう。
(あとは Naive UI もおすすめ)

環境構築

Tailwind は moduler が用意されてるので、とても簡単に導入できる。
PrimeVue は手動で入れていく。StyleMode がおすすめ。

参考:
https://nuxt.com/docs/getting-started/installation
https://tailwindcss.com/docs/guides/nuxtjs#modules
https://primevue.org/nuxt
https://primevue.org/icons/

$ npx nuxi@latest init nuxt3-primevue
> Which package manager would you like to use?
yarn

$ cd nuxt3-primevue

# install tailwind
$ npx nuxi module add @nuxtjs/tailwindcss
$ npx tailwindcss init

# install primevue
$ yarn add primevue @primevue/themes primeicons
$ yarn add --dev @primevue/nuxt-module

PrimeVue の設定を nuxt.config.ts に追記する。
テーマは大きく「Aura」と「Lara」がある。
Lara のほうが余白を大きくしたレイアウト。お好きなほうを。

nuxt.config.ts
import Aura from '@primevue/themes/aura';

export default defineNuxtConfig({
    modules: [
        '@primevue/nuxt-module',
    ],
    css: [
        'primeicons/primeicons.css',
    ],
    primevue: {
        options: {
            theme: {
                preset: Aura,
            },
        },
    },
})

App.vue にコンポーネントを入れてみて、使えるか確認する。

app.vue
<template>
  <div>
    <div class="bg-blue-500">
      <Button icon="pi pi-home" label="おうち"></Button>
    </div>

    <NuxtRouteAnnouncer />
    <NuxtWelcome />
  </div>
</template>

http://localhost:3000

image.png

導入成功!

1. ダッシュボードレイアウトを作る

大きく以下の項目に分かれる、よく見るレイアウト。

drawio (4).png

レイアウトは Nuxt の Layout 機能を使う。とても便利。

レイアウトを仮組みする

私は flex を多用してレイアウトを組みがちです。
それぞれの div に色を付けて、配置していきます。
(figuma とか使った方が現代的なんだろうけどさ...)

Layout を使うときは app.vue の中身を以下で上書きする。

app.vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

そして layouts/dashboardLayout.vue pages/index.vue のファイルを作成する。
(久々に触ったら Vue のファイル名、小文字が推奨されている...)

layouts/dashboardLayout.vue
<template>
  <div class="h-screen flex flex-col bg-red-800">
    <div class="h-[4rem] bg-orange-800">
      header
    </div>

    <div class="grow flex">
      <div class="w-[10rem] bg-blue-800">
        sidebar
      </div>

      <div class="grow bg-green-800">
        <slot />
      </div>
    </div>
  </div>
</template>
pages/index.vue
<template>
  <NuxtLayout name="dashboard-layout">
    content
  </NuxtLayout>
</template>

http://localhost:3000

image.png

ベースはこんなところ。
まず上下に区切って、余りを全て下に渡す。(flex flex-colgrow
次に下を左右に区切って、余りを全て右に渡す。(flexgrow

スクロールを考慮する

このままでは画面をはみ出したときに、サイドバーがつられてスクロールしてしまう。
必要なエリアのみがスクロールする方が、良い体験だと思っている。

色んな方法があるが、私は flex を多用する。(2回目)
今回は css variable を利用する。

layouts/dashboardLayout.vue
<template>
  <div class="h-screen flex flex-col bg-red-800"> <!-- (1) -->
    <div class="h-[var(--app-header-height)] bg-orange-800"> <!-- (2) -->
      header
    </div>

    <div class="grow h-[var(--app-header-height)] flex"> <!-- (3) -->
      <div class="w-[var(--app-sidebar-width)] overflow-auto bg-blue-800"> <!-- (4) -->
        sidebar
      </div>

      <div class="grow overflow-auto p-2 bg-green-800"> <!-- (5) -->
        <slot />
      </div>
    </div>
  </div>
</template>

<style lang="css">
:root {
  --app-header-height: 3.5rem;
  --app-sidebar-width: 12rem;
}
</style>

drawio (10).png

こんな感じ。

Animation.gif

ヘッダやサイドバーは大きさが固定なので、:root 要素に値を追加した。
こちらを使用することで、後で書き換えやすくしている。
そしてスクロールさせたい箇所に overflow-auto を付与した。

flex はお絵描きすると理解しやすい。
これで独立スクロールの完成。
通常はここまでで十分。

2. コンテンツにカードとテーブルを配置する

私がよくやるレイアウト。
content 領域にカードをフルサイズで配置して、カードの body だけスクロールさせたい。

drawio (6).png

こんな感じ。コンテンツ領域をスクロールするのではなく、テーブル要素だけスクロールさせる。
必要な要素だけスクロールさせると、目にとても良い。(個人の感想)
テーブルとか、現在の検索情報とか常に最上部にあってほしい。業務アプリならなおさら。

これらを使う:
https://primevue.org/card/
https://primevue.org/datatable/

pages/index.vue
<template>
  <NuxtLayout name="dashboard-layout">
    <Card <!-- (1) 内部 -->
      class="h-full"
      :pt="{
        body: 'h-full',
        content: 'h-full relative grow', <!-- (3) -->
      }"
    >
      <template #title> <!-- (2) -->
        たいとる<br>asd<br>asd
      </template>

      <template #content> <!-- (3) -->
        <div class="absolute size-full"> <!-- (5) -->
          <DataTable
            :value="items"
            scrollable
            :pt="{
              root: 'h-full',
              tablecontainer: 'h-full border',
              table: 'h-full',
              tbody: 'h-full',
              bodyrow: 'h-full',
              bodycell: 'h-full',
            }"
          >
            <Column field="id" header="ID" body-class="min-w-[2rem] max-w-[2rem]" />
            <Column field="product" header="商品名" body-class="min-w-[8rem] max-w-[8rem]" />
            <Column field="price" header="価格" body-class="min-w-[5rem] max-w-[5rem]"/>
            <Column field="qty" header="個数" body-class="min-w-[5rem] max-w-[5rem]"/>
            <Column field="note" header="説明文" body-class="whitespace-nowrap"/>
          </DataTable>
        </div>
      </template>

      <template #footer> <!-- (4) -->
        フッダ
      </template>
    </Card>
  </NuxtLayout>
</template>

<script setup lang="ts">
const items = computed(() => {
  return Array(50).fill({
    id: 1,
    product: 'たまねぎ',
    price: 100,
    qty: 5,
    note: '淡路島産のおいしいたまねぎです。とても甘く、たまねぎスープで食べるのがおすすめです。',
  })
})
</script>

drawio (9).png
こんな感じ。
ヘッダを増加させても問題なく伸縮できる。

Animation.gif

PrimeVue の pt 機能を使っているため、少しわかりにくい可能性あり。

テーブル要素を画面内でスクロールさせようとすると、高さを指定する必要が出てくる。
でも、描画時の高さは簡単には分からず、JavaScript で高さ計算を実装したことがある人も多いと思う。
またこの grow が厄介で、こいつ自身は高さ要素を持たない。
そのため、残った余りの高さを簡単に取り扱うことができない。。。

そこで!ポイントは二点!

  • h-screen を指定したタグからすべてのタグに h-full と 100% を使用する。
  • grow 要素に relative を付与して、その子供に abosolude size-full を使用する。

こうすることで、grow 要素はそのままに height: 100% が実現できるという。
この仕組みを知った時、とても感動した。。。

まとめ

PrimeVue いいよ!
使う人にやさしい UI 作ろうね!

(grid はまだ未勉強...)

1
0
0

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
  3. You can use dark theme
What you can do with signing up
1
0