4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Nuxt 3 + Vuetify 3 + TypeScript の事始め(appbarを出すところまで)

Posted at

概要

Nuxt 3 が 2022年4月にRC(Release Candidate)になったことで、今後、Nuxt 3での開発が中心になることも予想される。
また、それにあわせて、Vuetify3(執筆時点ではbeta版)、TypeScriptを組み合わせて、開発の環境設定+躓きそうなポイントをメモをしておく。

ドキュメント

環境

  • macOS Monterey 12.3.1 / Apple M1

  • Visual Studio Code / Volar-plugin

  • Node.JS

$ node -v
v16.13.1
  • npm
$ npm --v
8.1.2
  • Vueコマンド
$ vue --version
@vue/cli 5.0.4

手順

プロジェクト作成

まずはプロジェクトを作成してみましょう。nuxt3-test-appはプロジェクト名称ですので、お好きなものをつけてください。

$ npx nuxi init nuxt3-test-app

コマンドを実行してみましょう。nuxiがインストールされていない場合には、インストールするか聞かれますので、指示に従ってインストールしてください。実行結果が次のように出るはずです。/path/to/your/working/directory/はあなたが実行したディレクトリ配下のものが表示されます。

Nuxt CLI v3.0.0-rc.3                                                                                                                                  
ℹ cloned nuxt/starter#v3 to /path/to/your/working/directory/nuxt3-test-app                                                                                                                                                                                                                          
 ✨ Your stellar Nuxt project is just created! Next steps:
 📁  cd nuxt3-test-app                                                                                                                                
 💿  Install dependencies with npm install or yarn install or pnpm install --shamefully-hoist                                                         
 🚀  Start development server with npm run dev or yarn dev or pnpm run dev                                                                            ```

絵文字などと一緒に出ているのはとてもかわいいですよね。
さて、nuxt 3で作成されたデフォルトのセットをみてみますしょう。

$ cd nuxt3-test-app 
$ code .

Visual Studio Code が入っているのにもかかわらず、macOS で code . でVisual Studio Code が立ち上がらない場合には、環境変数が通っていないことが考えられます。

参考:M1 MacでVS Codeをターミナルから起動できるようにするまで

Visual Stuido Code を起動すると エクスプローラーに以下のように表示されているはずです。
image.png

どうです?最低限ですよね。

Nuxtの起動

ターミナルに戻ってnpm installをやってみましょう。

$ npm install  # working directoryで実行すること
npm WARN deprecated node-pre-gyp@0.13.0: Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future

added 647 packages, and audited 648 packages in 26s

77 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

続いてテスト実行してみましょう。

$ npm run dev
  > Local:    http://localhost:3000/ 
  > Network:  http://192.168.x.x:3000/

ℹ Vite server warmed up in 165ms                                                                                                                      
ℹ Vite client warmed up in 579ms                                                                                                                     
✔ Vite server built in 396ms                                                                                                                          
✔ Nitro built in 185 ms     

これが出たら成功です。ちなみに、Nitroは、Nuxt 3から搭載された実行エンジンです。詳しくは説明しませんが、公式サイトに以下のようなメリットがあると書かれています。

  • Cross-platform support for Node.js, Browsers, service-workers and more.
  • Serverless support out-of-the-box.
  • API routes support.
  • Automatic code-splitting and async-loaded chunks.
  • Hybrid mode for static + serverless sites.
  • Development server with hot module reloading.

さて、ブラウザで確認してみましょう。

http://localhost:3000/

image.png

こちらの画像が出れば、実行ができたということが確認できます。

ターミナルでcommand+cで実行を停止してみましょう。

Vuetify3のインストール

Vuetify3は執筆段階では、beta版です。なので、製品などへの組み込みは注意が必要です。

$ yarn add vuetify@next sass  

パッケージのインストール後、Visual Studio Codeに戻り、以下のpluginを作成してください。Nuxt 3は現段階ではVuetifyのプラグインがないため、自作する必要があるそうです。

plugins/vuetify.ts
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import { createVuetify } from 'vuetify'

export default defineNuxtPlugin((nuxtApp) => {
    const vuetify = createVuetify({
        components,
        directives,
    })

    nuxtApp.vueApp.use(vuetify)
})
nuxt.config.ts
import { defineNuxtConfig } from 'nuxt'

// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
    css: ['vuetify/lib/styles/main.sass'],
    build: {
        transpile: ['vuetify'],
    },
})

ページを作ってみる

app.vueをいじってみましょう。以前のNuxt2ではApp.vueでしたが、小文字になったようです。
app.vueはレイアウトファイルの元のような振る舞いをしているようです。
みていきましょう。
デフォルトだとシンプルなものになっています。真ん中のdivタグの中にある<NuxtWelcome /><NuxtPage />に変更してみてください。こうすることで、app.vueを使いつつ、具体的な中身はpagesディレクトリの配下を参照することができます。

app.vue(変更後)
<template>
  <div>
    <NuxtPage />
  </div>
</template>

pagesディレクトリ配下に2つファイルを作ってみましょう。

pages/aboutus.vue(新規作成)
<template>
    <h1>About us page</h1>
</template>
pages/welcome.vue(新規作成)
<template>
    <h1>Welcome to Our Nuxt 3 first page</h1>
</template>

これらを配置した上で、ターミナルからnpm run devで実行をしてみると、

http://localhost:3000/welcome
http://localhost:3000/aboutus

にアクセスできるようになります。

少し複雑なページにしてみる

コンポーネントを作ってみます。
v-app-barをラップしたHeaderのコンポーネントを作ってみました。pagesの以下のページは変更なしでよく、http://localhost:3000/aboutusにアクセスできることを確認してみましょう。

components/header/Header.vue(新規作成)
<template>
    <v-app-bar color="primary" id="app-bar">
        <template v-slot:prepend>
            <v-app-bar-nav-icon></v-app-bar-nav-icon>
        </template>

        <v-app-bar-title>Photos</v-app-bar-title>

        <v-menu open-on-hover>
            <template v-slot:activator="{ props }">
                <v-btn v-bind="props" icon="mdi-dots-vertical">
                </v-btn>
            </template>
            <v-list dark dense>
                <v-list-item v-for="menu in items" :key="menu.no" link>
                    <v-list-item-title>{{ menu.title }}</v-list-item-title>
                </v-list-item>
            </v-list>
        </v-menu>
    </v-app-bar>
</template>

<script>
export default {
    data: () => ({
        items: [
            { no: 1, title: 'About us' },
            { no: 2, title: 'プライバシーポリシー' },
            { no: 3, title: '利用規約' },
            { no: 4, title: 'ログアウト' },
        ],
        closeOnContentClick: true,
    }),
}
</script>
layouts/custom.vue(新規作成)
<template>
    <v-app>
        <div>
            <header>
                <Header />
            </header>
            <v-main>
                <slot />
            </v-main>
        </div>
    </v-app>
</template>

<script setup>
import Header from "@/componets/header/Header.vue";
</script>
app.vue(変更)
<template>
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css" rel="stylesheet">

    <NuxtLayout name="custom">
        <NuxtPage />
    </NuxtLayout>
</template>
pages/aboutus.vue(変更)
<template>
    <h1>About us page</h1>
    This is aboutus page 1<br />
    This is aboutus page 2<br />
    This is aboutus page 3<br />
    This is aboutus page 4<br />
    This is aboutus page 5<br />
    This is aboutus page 6<br />
</template>

ちゃんとできるかと思ったのですが、私の環境・Vuetifyのバージョン(beta 2)では、次のようになってしまいました。
ロード後にappbarが画面幅よりも小さいのが出て、しばらくしてから画面幅最大にappbarが引き延ばされるという仕様でした。

appbar 2.gif

違う方法でappbarっぽいのを実装してみる

v-toolbar / v-btn を利用して、v-app-barっぽいものを実装してみました。Vuetify 3.0が正式版になればなおるであろうことではありますが、今少し困っているので無理矢理対応してみました。
しかし、こちらのソースコードでは、ナビバーの右側のボタンが反応しませんでした。
(左側のハンバーガーメニューはそもそも実装していませんので、反応しません。)

components/header/OriginalHeader.vue(新規作成)
<template>
    <v-toolbar color="primary">
        <v-btn color="white" icon="mdi-menu">
        </v-btn>
        <v-toolbar-title>xxxシステム</v-toolbar-title>

        <v-spacer></v-spacer>

        <v-menu open-on-hover>
            <template v-slot:activator="{ on }">
                <v-btn v-on="on">
                    <v-icon icon="mdi-dots-vertical"></v-icon>
                </v-btn>
            </template>

            <v-list dark dense>
                <v-list-item v-for="item in items" :key="item.no" link>
                    <v-list-item-title>{{ item.title }}</v-list-item-title>
                </v-list-item>
            </v-list>
        </v-menu>
    </v-toolbar>
</template>

<script>
export default {
    data: () => ({
        items: [
            { no: 1, title: 'About us' },
            { no: 2, title: 'プライバシーポリシー' },
            { no: 3, title: '利用規約' },
            { no: 4, title: 'ログアウト' },
        ],
        closeOnContentClick: true,
    }),
}
</script>
layouts/custom.vue(変更)
<template>
    <v-app>
        <OriginalHeader />
        <v-main>
            <slot />
        </v-main>
    </v-app>
</template>

<script setup>
import OriginalHeader from "@/components/header/OriginalHeader.vue";
</script>

image.png

成功例appbar

v-menuのところの書き方をv-btnを親タグとして書き、それを参照する形でv-menuを内包する書き方だと、hoverがうまく動きました。ただ、メニューが少し切れてしまっております。left offset-xなどを試してみましたが、うまく反応しておりません。

components/header/OriginalHeader.vue(変更)
<template>
    <v-toolbar color="primary">
        <v-btn color="white" icon="mdi-menu">
        </v-btn>
        <v-toolbar-title>xxxシステム</v-toolbar-title>

        <v-spacer></v-spacer>

        <v-btn color="white" dark>
            <v-icon icon="mdi-dots-vertical"></v-icon>
            <v-menu activator="parent" :open-on-hover="true" left offset-x nudge-left="100">
                <v-list>
                    <v-list-item v-for="item in items" :key="item.no" link>
                        <v-list-item-title>{{ item.title }}</v-list-item-title>
                    </v-list-item>
                </v-list>
            </v-menu>
        </v-btn>
    </v-toolbar>
</template>

<script>
export default {
    data: () => ({
        sticky: false,
        items: [
            { no: 1, title: 'About us' },
            { no: 2, title: 'プライバシーポリシー' },
            { no: 3, title: '利用規約' },
            { no: 4, title: 'ログアウト' },
        ],
        closeOnContentClick: true,
    }),
}
</script>

image.png

おわりに

Vuetify 3.0 beta2で試してみましたが、まだまだ情報が少ないのが現状です。そのうち修正される内容だらけだと思いますが、何かの参考になれば幸いです。(間違い、認識間違いがあったら申し訳ございません。)

4
4
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
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?