Vue.jsでWebアプリを作ろう~モックアップ作成編~

Web開発

こんにちは、Vue.js企画第三段です。
前回、前々回とVue.jsで開発をするための下準備や環境構築をおこなってきました。
良ければ前回の記事もご覧いただけるとスムーズに開発も行えるかと思います。

大規模なアプリケーションを作成する場合はNuxt.jsなどのフレームワークを利用したり、Vue CLIを利用して雛形をコマンド一発で作成することもできるかと思いますが、今回は勉強も兼ねているためそれらのツールは使用せずに、Vue.jsのみを使ってアプリ作成していこうと思います。

ディレクトリ構成を検討する

コーディングする前にディレクト構成を検討します。
今回作成するような簡単なアプリであれば正直どうでも良いのですが、大規模なアプリケーションだとあとになってディレクトを整理するのって結構面倒なんですよね。

VueやReactなどのアプリはどうしてもファイル数が多くなってしまうので、大規模なアプリケーションを作成するつもりの方は事前に検討されることをオススメします。

自分は以下のようにしました。

- /
 - src
   - public
     - index.html
     - images
     - js
   - resorces
     - components
     - index.js
 - node_modules
 - .editorconfig
 - .gitignore
 - pakage.json
 - webpack.config.js
  • public ・・・ 公開ディレクト
    • 配下に画像を格納するimagesとWebpackでバンドルしたJSを格納するためのjsを配置
  • resorces ・・・ Vue.jsのファイルを格納するためのディレクト
    • 配下にコンポーネントファイルを格納するためのcomponentsを配置
  • node_modules ・・・ npmインストールしたライブラリのインストール先

公開するHTMLを作成

公開するHTMLを作成していきます。
また、今回はCSSのフレームワークとしてBootstrap5 を使います。

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>サンプルアプリケーション</title>

  <!-- bootstrapをCDNからインストール -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
    crossorigin="anonymous"></script>
</head>

<body>
  <!-- ナビゲーションバー -->
  <nav class="navbar navbar-light bg-light">
    <div class="container">
      <a class="navbar-brand" href="#">
        <img class="align-text-top" src="./images/icon.png" alt="" width="35" height="29">
        サンプルアプリケーション
      </a>
    </div>
  </nav>

  <!-- Vueインスタンスが展開されるタグ -->
  <div id='app'></div>

  <!-- バンドルしたJSを読み込み -->
  <script src="./js/bundle.js"></script>
</body>

</html>

共通のナビゲーションバーはHTMLにベタ書きしてしまいます。
また、Vueのエントリポイントがマウントするためのタグを忘れずに記載します。

エントリポイントの作成

エントリポイントと呼ばれる最初に読み込まれるプログラムを作成していきます。
resorcesディレクトリ直下に「index.js」という名前で作成します。

import Vue from 'vue';
import App from './comporent/App.vue';

new Vue({
    render: h => h(App),
}).$mount('#app');

1行目でインストールしたVueの本体を読み込んでいます。
2行目は後述するコンポーネントを読み込んでいます。

4行目以下でVueインスタンスを生成し、前述したHTMLのdivタグのIDを指定しています。
また読み込んだコンポーネントを忘れずに設定してください。

コンポーネントの作成

コンポーネントを作成していきます。
コンポーネントに関する詳しい説明は、ぜひ公式ドキュメントを参照ください。

resorces/componentsディレクトリの下に、3つのコンポーネントを作成していきます。

・ルートコンポーネント
・ログイン画面用のコンポーネント
・ダッシュボード画面用のコンポーネント

順番に説明していきます。

ルートコンポーネント(App.vue)
エントリポイントが読み込むためのコンポーネントです。
各コンポーネントをルーティングするような役割も担っています。

<template>
    <div class="container mt-5">
        <Login v-if="!loginFlg" :loginId="loginId" :password="password" @validation="validateLoginInfo"></Login>
        <Dashbord v-else :articles="articles"></Dashbord>
    </div>
</template>

<script>
import Login from './Login';
import Dashbord from './Dashbord';

export default {
    data() {
        return {
            loginId: '',
            password: '',
            loginFlg: false,
            articles: [
                {id: 1, title: 'ブログタイトル1', status: true, person: 'テスト太郎'},
                {id: 2, title: 'ブログタイトル2', status: false, person: 'テスト花子'},
                {id: 3, title: 'ブログタイトル3', status: false, person: 'テスト花子'},
                {id: 4, title: 'ブログタイトル5', status: true, person: 'テスト太郎'},
                {id: 5, title: 'ブログタイトル6', status: true, person: 'テスト太郎'},
                {id: 6, title: 'ブログタイトル7', status: false, person: 'テスト花子'},
                {id: 7, title: 'ブログタイトル8', status: false, person: 'テスト次郎'},
                {id: 8, title: 'ブログタイトル9', status: false, person: 'テスト花子'},
                {id: 9, title: 'ブログタイトル10', status: false, person: 'テスト次郎'},
            ]
        }
    },
    methods: {
        validateLoginInfo(id, pass) {
            this.$nextTick(function() {
                this.loginFlg = id != '' && pass != '';
            });
        }
    },
    components: {
        Login,
        Dashbord
    }
}
</script>

template内に子コンポーネントのLoginとDashBordを配置しています。
擬似的なログイン機能を実現するために、v-ifディレクティブでloginFlgを参照して表示するコンポーネントを切り替えています。

また、script内には子コンポーネントで利用するための、データの初期化を行います。
ログインに必要な、ID、パスワード、ログインフラグ、ダッシュボードに表示するサンプルデータをそれぞれ定義して、初期化しています。

超簡易的なログイン機能をmethodに定義します。
ログインが成功したらダッシュボードを描画しないといけないので、$nextTickに渡すコールバック関数内でログイン機能を定義します。

ログイン画面用のコンポーネント

ログイン画面のコンポーネントです。

<template>
<div class="container mt-5">
    <div class="card shadow">
        <div class="card-body">
            <form @submit.prevent="validate">
                <div class="mb-3">
                    <label for="exampleInputEmail1" class="form-label">ログインID</label>
                    <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
                </div>
                <div class="mb-3">
                    <label for="exampleInputPassword1" class="form-label">パスワード</label>
                    <input type="password" class="form-control" id="exampleInputPassword1">
                </div>
                <div class="mb-3 d-grid gap-2 col-6 mx-auto">
                    <button type="submit" class="btn btn-primary">ログイン</button>
                </div>
            </form>
        </div>
    </div>
</div>
</template>

<script>
    export default {
        props: [ 'loginId', 'password' ],
        methods: {
            validate() {
                this.$emit('validation');
            }
        }
    }
</script>

親コンポーネントから受け取ったpropsとmethodを子コンポーネント内で利用できるよう、script内で定義しているのがポイントです。

ダッシュボード画面用のコンポーネント

最後にログインが成功した場合に表示するダッシュボード画面のためのコンポーネントです。

<template>
    <div class="row">
        <p class="h3 mb-3 text-muted">ブログ記事一覧</p>
        <table class="table table-hover">
            <thead>
                <tr>
                    <th scope="col">No</th>
                    <th scope="col">ブログタイトル</th>
                    <th scope="col">公開状態</th>
                    <th scope="col">作成者</th>
                    <th scope="col">編集</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="article in articles" :key="book.id">
                    <th scope="row">{{ article.id }}</th>
                    <td>{{ article.title }}</td>
                    <td>{{ article.status ? '公開': '非公開' }}</td>
                    <td>{{ article.person }}</td>
                    <td>
                        <button type="button" class="btn btn-primary" v-bind:disabled="article.status">編集する</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script>
export default {
    props: [ 'article ' ],
    methods: {
    }
}
</script>

親コンポーネントから受け取ったデータをテンプレート内で表示するだけの単純なものです。

ローカル環境で確認

ここまで作成できたらwebpackのローカルサーバー機能を利用して動作確認してみます。

$ npm run serv

ローカルサーバーを立ち上げるとログイン画面が表示されます。
適当なログインIDとパスワードを入力してログインボタンを押下してみます。

ログインが成功してダッシュボードが表示されました。
設定したデータも正しく表示されていますね。

問題なく動作しているようです。

まとめ

非常に簡単ではありますが、Vue.jsでモックアップの作成をしてみました。
今回は素のVue.jsで書いたのですが、今後はNuxt.jsやVue-routerなどのフレームワーク、ライブラリも調べて組み込んでみたいと思います。

仕事ではSI業務がメインなので、久々にプログラミングっぽいことをしたのですが、やはり自分でコーディングして動くものを触るのは楽しいですね。

次回以降の記事でリファクタリングしていこうと思います!

ではでは~~

コメント

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