Vue.jsでとりあえずサイトを作る [初心者向け]

## 始めに
### 概要
レッスン形式で簡単なサイト(Vue.jsの紹介サイト)を作ることで、Vue.jsへの理解を深める。

Vue.jsを触ったことのない人向けで、仕組みの理解は置いておいて、まずは動くものを作ることを目指す。
HTMLとCSSの知識さえあれば、理解できるように書いた。

本記事では、Vue3のCompositionAPIを使い、ビルドツールとしてViteを用いる。

:::note warn
わかりやすさを優先するため、不十分もしくは正確性を欠いた説明がある。
:::

:::note info
コードのコピペだけで終わらず、色々変えて試しながら進めることを推奨する。
:::

### 本記事のゴール
次のような、Vue.jsを簡単に紹介するサイトを作る。

https://m-haruki.github.io/LearnVueJs/

![IMG_1924.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/a439e0d5-8f07-41b5-865c-43a4b647a708.png)


### 対象者・前提条件
- HTML・CSSをある程度、読み書きできる
- [VisualStudioCode](https://code.visualstudio.com/)と[Node.js](https://nodejs.org/ja)導入済みのPCもしくは、[GitHubCodespaces](https://github.co.jp/features/codespaces)を開ける環境

### Vue.jsとは
人気のあるJavaScriptフレームワーク。
素のHTMLなどにない機能が使えるため楽に開発でき、特にJSは格段に書きやすくなる。
公式ドキュメントが日本語化されていて読みやすいため、適宜参考にするとよい。

https://ja.vuejs.org/

### Codespacesとは
Codespacesとは、ブラウザから使えるコードエディタ(VSCode)である。
最低限の使い方は、次のサイトを参考にするとよい。

https://docs.github.com/ja/codespaces/getting-started/quickstart

https://zenn.dev/protoout/articles/68-github-codespaces-setup

### 執筆時のバージョン
|名称|バージョン|
|-|-|
|Node.js|v20.18.1|
|npm|10.8.2|
|Vue.js|3.15.1|
|Vite|v6.1.0|

## プロジェクトの作成
VSCodeでフォルダを開いた状態か、Codespacesでリポジトリを開いた状態から始める。

### Vue.jsテンプレートの作成
ターミナルに次のコマンドを打つ。
```shell
npm create vue@latest
```

`Ok to proceed?`と聞かれるので、`y`と打ちエンターキーで確定する。
`Project name`を聞かれるので、プロジェクト名を入力して確定する。
`Package name`を聞かれるが、プロジェクト名からサジェストされているので、そのまま確定すればいい。

機能の一覧から、矢印キーで機能を選び、スペースキーで有効化、必要なものを全て有効化できたらエンターキーで確定する。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/ab5accad-9d17-43e5-97e0-7d59c40d6de2.png)
各機能の説明はおおよそ次の通り。VueRouter以外は無効化のままでも良い。
|項目名|推奨|説明|
|-|-|-|
|TypeScript|x|JavaScriptの拡張であるTypeScript|
|JSX Support|x|JSXの構文のサポート|
|Router|o|複数ページのサイトを作るために使うVueRouter (本記事の内容を実施するには必須)|
|Pinia|x|状態管理ライブラリPinita|
|Vitest|x|テストフレームワーク|
|End-to-End Testing|x|エンドツーエンドのテストフレームワーク|
|ESLint|o|静的コード解析ツールEslint|
|Prettier|o|コードフォーマッターPrettier|

ESLintを有効化すると、`Instal Oxlint for faster linting? (experimental)`などと聞かれることがあるが、試験的とあるので`No`を選択すればいい。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/eea065ec-5399-447d-b5a7-ccc2aa6408e2.png)

<details>
<summary>
古いバージョンの場合
</summary>

矢印キーで各機能の有効/無効を選択しエンターで確定する。
![IMG_1920.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/0fd8143d-7c59-4ce8-be2d-1e3ceadc4427.png)
機能の各項目の意味は、おおよそ次の通り。VueRouter以外は、わからなければNoを選んでもいい。
|項目名|推奨|説明|
|-|-|-|
|Ok to proceed?|y|本当にプロジェクトを作成するかを問われている|
|Project name|任意|プロジェクト名|
|Package name|任意|パッケージ名、サジェストされているものをそのまま選択すればいい|
|Add TypeScript?|No|JavaScriptの代わりにTypeScriptを使うかどうか|
|Add JSX Support?|No|JSXの構文をサポートするかどうか|
|Add Vue Router for Single Page Application development?|Yes|複数ページのサイトを作るために使うVueRouterを有効かするかどうか(本記事の内容を実施するには必須)|
|Add Pinia for state management?|No|状態管理ライブラリPinitaを有効にするかどうか|
|Add Vitest for Unit Testing?|No|テストフレームワークVitestを有効にするかどうか|
|Add an End-to-End Testing Solution?|No|エンドツーエンドのテストフレームワークを有効にするかどうか|
|Add ESLint for code quality?|Yes|静的コード解析ツールEslintを有効にするかどうか|
|Add Prettier for code formatting?|Yes|コードフォーマッターPrettierを有効にするかどうか|
</details>

完了すると、`Done. Now run: ...`と表示されて、プロジェクト名のフォルダが作られる。

### プレビュー
ターミナルに表示されたとおり、下記のコマンドを打って開発用サーバーを立ち上げる。
```shell
cd プロジェクト名 #プロジェクトフォルダへ移動(例 cd LearnVueJs)
npm install #必要なものをインストールする(npm iと省略できる)
npm run dev #開発用サーバーを起動する
```

![IMG_1921.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/77286dff-c78d-4a76-9a07-75dff4ff3c95.png)

VSCodeであればターミナルに出てきた`http://localhost:5173/`などのURLをタップして、Codespacesであれば右下の`ブラウザーで開く`もしくはポートタブから、プレビュー画面を開ける。
次のようなVue.jsの初期ページが表示されているはずだ(バージョンや機能によって表示されるページは多少異なる)。

![IMG_1922.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/b74fd60d-5039-4265-8414-0a3720116aef.png)

## ページ作成
これからページを作っていく。

:::note warn
これ以降のファイルは、プロジェクト名のフォルダからのパスで表す。
:::


### 共通のCSS(main.css)
まずは、`src/assets/main.css`の内容を削除し、次の内容を書き込む。
```css:src/assets/main.css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
```
このCSSファイルに書いた内容はページ全体に適用されるので、全要素へ指定するスタイルや、テーマカラーの指定などを書くことが多い。

### App.vue
テンプレートの内容が邪魔になってしまうため`src/App.vue`の内容を全て削除し、次のように書き換える。
```vue:src/App.vue
<template>
  <RouterView></RouterView>
</template>
```
### Homeページ(Vueファイルの書き方)
まずはHomeページを作る。

`src/views/HomeView.vue`の内容を全て消し、今回はVueを紹介するということで、次のように書き換える。
```vue:src/views/HomeView.vue
<template>
  <div class="home-view">
    <h1>Vue.jsの紹介</h1>
    <p>
      Vue.jsは、人気のあるJavaScriptフレームワークです。
      <br>
      シンプルで柔軟なAPIを提供し、リアクティブなデータバインディングとコンポーネントベースのアーキテクチャを特徴としています。
    </p>
    <ul>
      <li>リアクティブなデータバインディング</li>
      <li>コンポーネントベースのアーキテクチャ</li>
      <li>シンプルで柔軟なAPI</li>
      <li>豊富なエコシステムとプラグイン</li>
    </ul>
    <p>
      Vue.jsは、単一ページアプリケーション（SPA）や複雑なフロントエンドプロジェクトの開発に適しています。
    </p>
  </div>
</template>
<style scoped>
.home-view {
  padding: 20px;
}

h1 {
  color: #42b983;
  font-size: 2rem;
  margin-bottom: 20px;
}

p {
  font-size: 1.2rem;
  margin-bottom: 10px;
}

ul {
  list-style-type: disc;
  padding-left: 1.5rem;
}

li {
  font-size: 1rem;
  margin-bottom: 0.5rem;
}
</style>
<script setup>
// JavaScript here
</script>
```
先ほど開いたプレビューを確認すると、書いたコードが反映されていることが確認できる。

Vueファイル(拡張子が`vue`)では、templateタグの中にHTMLを、styleタグの中にCSSを、scriptタグの中にJavaScriptを書く。
それぞれ特殊な記法はあるものの、基本は普通のHTMLなどと一緒である。

### Aboutページ
次にAboutページを作る。

`src/views/AboutView.vue`の内容を全て消し、サイトに関しての説明として、次のように書き換える。
```vue:src/views/AboutView.vue
<template>
  <div class="about-view">
    <h1>このサイトについて</h1>
    <p>このサイトは、Vue.jsの学習用に作成されました。</p>
    <p>Vue.js公式とは無関係のサイトです。</p>
  </div>
</template>

<style>
.about-view {
  padding: 20px;
}

h1 {
  color: #42b983;
  font-size: 2rem;
  margin-bottom: 20px;
}

p {
  font-size: 1.2rem;
  margin-bottom: 10px;
}
</style>
```

プレビューのURLの末尾に`/about`をつけて、書き換えてアクセスすると、書いたコードが反映されていることを確認できる。

Homeページとやっていることは同じである。
styleタグとscriptタグは省略可能なため、scriptタグを省略した。

### 別ページへのリンクを追加する(RouterLink)
HomeページとAboutページを行き来するためのリンクを書く。
HomeView.vueのtemplateタグの最後の方に次のように追記する。
```vue:src/views/HomeView.vue(一部)
    </p>
    <br>
    <RouterLink to="/about">このサイトは何?</RouterLink>
  </div>
</template>
```
プレビュー画面でhomeのページに戻ると、リンクが追加されているだろう。
`<a href="/about">About</a>`でも動作するが、aタグの代わりに`<RouterLink to="/about">About</RouterLink>`
と書くとロードを挟まないページ遷移を実現でき、好ましい。
外部ではないプロジェクト内へのリンクは、基本RouterLinkで書くべきだ。

### 画像を追加する(パスの指定方法)
Vueのロゴ画像を追加するため、HomeView.vueのtemplateタグの最初の方に次のように追記する。
```vue:src/views/HomeView.vue(一部)
<template>
  <div class="home-view">
    <h1>Vue.jsの紹介</h1>
    <img src="@/assets/logo.svg" alt="Vueのロゴ画像">
    <p>
```
また、それに合わせてstyleタグ内のCSSも書き加える。
```css:src/views/HomeView.vue(一部)
}

img {
  width: 100px;
}
</style>
```

再びプレビューを見ると、ロゴ画像が追加されているだろう。
imgタグのsrcへ指定したように、`src/assets/`フォルダに置いたコンテンツへは、`@/assets/logo.svg`とすることでアクセスできる。
`@`を使うと、srcフォルダからのパスでファイルを指定できる。
相対パスも使えるが、`@`を使ったパス指定の方が確実で安全だと思われる。

## ページの追加(VueRouter)
### VueRouterの設定変更(router/index.js)
`src/router/index.js`のroutesという配列に次の内容を追加する。
```js
    {
      path: '/links',
      name: 'links',
      component: () => import('../views/LinksView.vue'),
    },
```
index.js全体は次のようになる。
```js:src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView,
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue'),
    },
    {
      path: '/links',
      name: 'links',
      component: () => import('../views/LinksView.vue'),
    },
  ],
})

export default router
```
このファイルは、VueRouterというルーティングライブラリの設定ファイルだ。
ページを増やすときは、そのページのパス(どういったURLでアクセスできるサイトか)と、固有の名前、ページのVueファイルのパスを、今回のように追記する。

### Vueファイルの追加
今指定したLinksView.vueというファイルを作る。
`src/views/`に`LinksView.vue`というファイルを作成し、リンク集としての次の内容を書き込む。
```vue:src/views/LinksView.vue
<template>
    <div class="links-view">
        <h1>Vue.js学習に役立つリンク集</h1>
        <ul>
            <li><a href="https://vuejs.org/" target="_blank">公式サイト</a></li>
            <li><a href="https://vuejs.org/guide/" target="_blank">公式ガイド</a></li>
            <li><a href="https://vuejs.org/api/" target="_blank">APIリファレンス</a></li>
            <li><a href="https://router.vuejs.org/" target="_blank">Vue Router</a></li>
            <li><a href="https://vuex.vuejs.org/" target="_blank">Vuex</a></li>
            <li><a href="https://vuetifyjs.com/en/" target="_blank">Vuetify</a></li>
            <li><a href="https://vue-loader.vuejs.org/" target="_blank">Vue Loader</a></li>
        </ul>
    </div>
</template>

<style scoped>
.links-view {
    padding: 20px;
}

h1 {
    color: #42b983;
    font-size: 2rem;
    margin-bottom: 20px;
}

p {
    font-size: 1.2rem;
    margin-bottom: 10px;
}

ul {
    list-style-type: disc;
    padding-left: 1.5rem;
}

li {
    font-size: 1rem;
    margin-bottom: 0.5rem;
}
</style>
```
Vueファイルなので、やっていることは先程のHomeやAboutと同じである。

プレビューのURLの末尾に`/links`をつけて、書き換えてアクセスすると、今作ったページができているだろう。

## 全ページ共通要素の追加(App.vue)
`src/App.vue`の内容を次のように書き換えて、サイト全体のヘッダーを作る。
```vue:src/App.vue
<template>
  <header>
    <nav>
      <ul>
        <li>
          <RouterLink to="/">ホーム</RouterLink>
        </li>
        <li>
          <RouterLink to="/about">このサイトについて</RouterLink>
        </li>
        <li>
          <RouterLink to="/links">リンク集</RouterLink>
        </li>
      </ul>
    </nav>
  </header>
  <RouterView></RouterView>
</template>

<style scoped>
header {
  background-color: #42b983;
  padding: 10px 20px;
}

nav ul {
  list-style: none;
  display: flex;
  gap: 20px;
  padding: 0;
  margin: 0;
}

nav li {
  display: inline;
}

nav a {
  color: white;
  text-decoration: none;
  font-size: 1.2rem;
}

nav a:hover {
  text-decoration: underline;
}
</style>
```
プレビューにヘッダーが追加されているだろう。

すべてのページはApp.vueの中に表示されていて、VueRouterは、RouterViewタグの中に入る内容を変えることでページ遷移を実現している。
App.vue自体を書き換えることで、どのページでも共通して表示される要素を実装できる。

## コンポーネントの追加
### コンポーネントの作成
`src/components/`に`OfficialLink.vue`というファイルを作成し、公式サイトへのリンクを構成する、次の内容を書き込む。
```vue:src/components/OfficialLink.vue
<template>
    <div>
        <a href="https://vuejs.org/">Vue.js公式サイトはこちら</a>
    </div>
</template>
<style scoped>
div {
    margin-top: 50px;
}

a {
    display: inline-block;
    padding: 10px 20px;
    background-color: #42b983;
    color: white;
    text-decoration: none;
    border-radius: 5px;
}

a:hover {
    background-color: #369870;
}
</style>
```

### コンポーネントの利用
このボタンを設置したいページ、HomeView.vueとAboutView.vueのscriptタグを下記のように改変または追加する。
```vue
<script setup>
import OfficialLink from '@/components/OfficialLink.vue'
</script>
```
そして、読み込んだページの各templateタグの最後の方に、OfficialLinkタグを設置する。
```vue
    <OfficialLink />
  </div>
</template>
```

プレビューを確認すると、homeページとaboutページに、同じ公式サイトへのリンクが追加されているだろう。
このように、Webサイトのパーツをコンポーネントとして、新たなVueファイルに切り出すことで、再利用できるようになる。

## 終わりに
### 完成形
改めて完成形はこんな感じだ。

https://m-haruki.github.io/LearnVueJs/

![IMG_1924.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692292/a439e0d5-8f07-41b5-865c-43a4b647a708.png)

また、今回のソースコード全体はこちらから確認できる。

https://github.com/M-Haruki/LearnVueJs

### この後のおすすめ
今回は触れなかったが、Vue.jsの本来の強みであるJSを書けると、より多くの機能を実装できるようになる。
Vue.jsでのJSを知るには、下記の公式チュートリアルがおすすめだ。
この内容をやった後であればどう役立つかもわかりやすいと思う。

https://ja.vuejs.org/tutorial/

## 参考文献
https://ja.vuejs.org/

https://qiita.com/KUMA_TR/items/56f53ac952df12c7c450

https://qiita.com/yutoun/items/d61595530f3384e7e3ee

https://macocci7.net/blog/2024/01/21/%E3%80%90vue-js%E3%80%91%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92github-pages%E3%81%AB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/