Laravel+Vueでフォーム作成ツールを制作【ホーム画面を作ろう】

Developments PHP Programming

こんにちは。あきのです。一般人です。

今回は、フォーム作成ツールのホーム画面を作りましょう。
イメージはこんな感じ。
ホーム画面

ここで学べることは。。。

  • Vue.jsのコンポーネント作成
  • Vue.jsのrouter(URL設定)の使い方
  • Laravelのコンポーネント作成

では、さっそくやっていきましょう。

・環境情報
OS: Windows10
ローカル開発環境ツール:XAMPP
サーバー:Xserver

・使用言語
PHP: 7.4.11
Laravel: 8.29.0
Vue.js: 2.6.12
MySQL: 5.7以上
tailwindcss: 2.0.3

XAMPP, Node.js, composerはすべて用意済みという仮定で進めていきます。
ソースコード全体はこちら

プロジェクトの作成

まず、Laravelプロジェクトの作成をしていきます。
ターミナル(Power Shell)などを開いて以下のコマンドを入力。

composer create-project laravel/laravel setform

最後の”setform”は好きな名前で大丈夫ですが、統一させたい場合はこの名前にしてください。

入力後、ファイルの作成が行われますがちょっと長いです。ゆっくりしながら待ちましょう。

作成し終えたら、エディタ(VS codeなど)で開きます。

また、以下のコマンドを実行しておきましょう。

php artisan storage:link

これはstorageフォルダ内にあるファイルをpublicから参照できるようにするコマンドです。
本来はpublicフォルダにあるものしかアクセスできないのですが、これにより間接的にstorage内にあるファイルを取り出すことができるようになります。

Vue.jsなどをインストール

ターミナルで作成したプロジェクトに移動して以下のコマンドを打ちます。

npm install

するといろいろファイルが作成されていきます。

完了した後、package.jsonというファイルを開いて見てください。
その中のdevDependenciesを以下のようにしましょう。


"devDependencies": {
        "autoprefixer": "^10.2.4",
        "axios": "^0.21.1",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.2.6",
        "resolve-url-loader": "^3.1.2",
        "sass": "^1.32.8",
        "sass-loader": "^8.0.2",
        "tailwindcss": "^2.0.3",
        "vue": "^2.6.11",
        "vue-loader": "^15.9.5",
        "vue-template-compiler": "^2.6.11",
        "vue-router": "^3.5.1"
    },

その後、もう一度npm installを実行してください。
ここでやっていることは主に…

  • Vue.jsを使えるようにする
  • tailwindcssを使えるようにする
  • sassを使えるようにする

コンパイル設定

webpack.mix.jsを開きます。
コメントより下にあるmix.js...の部分を編集します。

mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/router.js', 'public/js')
    .vue()
    .sass('resources/sass/main.scss', 'public/css')
    .postCss('resources/css/app.css', 'public/css', [
        require('tailwindcss'),
    ]);

ここでやっていること。

ここでは、jsファイルやcssファイルの更新です。

WebページはCSSやJavaScriptの文法でしか動きません。
なのでVue.jsの文法は、Javascriptの文法に書き換えてあげないといけないということです。
その書き換えをここでやっています。

書き換えを実行するためにはターミナルで以下のコマンドを打ちます。


npm run dev
//または
npm run watch

npm run devは1回だけ実行。npm run watchはファイルが編集されるたびに自動で実行してくれます。
後者のコマンドを使った方が今後は良いと思います。

bladeでレイアウトを作成

ホーム画面の大枠を作っていきます。
まず、以下のコマンドでサーバーを立ち上げます。

php artisan serve


今こんな感じになっているかと思います。

これは、resources/views/welcome.blade.phpが表示されています。
これを完成形のホーム画面にしていきます。

共通部分のコンポーネントを作成

まずは、ヘッダーなどの共通部分をコンポーネント化していきます。

ターミナルでコマンドを打ちます。

php artisan make:component AppLayout

これでapp/View/Components/AppLayout.phpというファイルができると思います。
この中にあるrenderメソッドの中身を変更していきます。


public function render()
    {
        return view('layouts.app');
    }

次に、resources/views/layouts/app.blade.phpを作成します。
このファイル内には以下のようなコードを作ります。


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>{{config('app.name', 'Set Form')}}</title>

        <!-- Fonts -->
        <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
        <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.2/css/all.css" integrity="sha384-vSIIfh2YWi9wW0r9iZe7RJPrKwp6bG+s9QZMoITbCckVJqGCCRhc+ccxNcdpHuYu" crossorigin="anonymous">

        <!-- Styles -->
        <link rel="stylesheet" href="{{mix('css/app.css')}}">
        <link rel="stylesheet" href="{{mix('css/main.css')}}">
            
    </head>
    <body class="antialiased">
        <div id="app">
            <x-header></x-header>
    
            <main class="py-8 bg-gray-100">
                {{$slot}}
            </main>
        </div>


        <!-- JS -->
        <script src="{{mix('js/app.js')}}" defer></script>
    </body>
</html>

ここでやっていること

これは、どのページに行っても使う共通のコードを書いています。
例えば、cssファイルやjsファイルをここで読み込むことで今後作っていくファイルにいちいち読み込みコードを書く必要が無くなります。

また、bodyの中では、headermainに分けています。
x-headerは後程作るheaderコンポーネントを読み込むコードです。

mainタグには{{$slot}}という記述がありますが、ここには今後作っていくページが読み込まれていきます。

あと、<div id="app">で一部囲っていますが、これはvue.jsを使う上で大事なので勝手に変更などはしないように。

cssファイル, jsファイル, headerコンポーネントを作成

このファイルでは、cssファイル、jsファイル、headerコンポーネントを読み込んでいるのでこれらのファイルも作成します。

それぞれは以下のように作成してください。
resources/css/app.cssは以下のようにします。


//tailwind cssを利用するための記述
@tailwind base;
@tailwind components;
@tailwind utilities;

//以下にwelcome.blade.phpに書かれているstyleタグの中身を貼りつけ

最初の3行はtailwind cssを利用するためのコードです。tailwind cssというものがあまり聞きなれないかもしれませんが、bootstrapのようなものだと今は認識しておいてください。

resources/js/app.jsは以下の通りです。


require('./bootstrap');
//vueのインポート
import Vue from 'vue'
import router from './router'

//vue.jsを使うための初期設定
const app = new Vue({
    el: '#app',
    router: router,
})

最初の数行でvueとrouterをインポートしておきます。

そして、Vueインスタンスというものを作ります。つまり初期設定です。
elはvue.jsを適用するタグのid属性を入れます。これは先ほどのapp.blade.phpで説明したdivタグです。

routerは後程説明しますがurlの設定のことです。

最後にresources/components/header.blade.phpを作成してコードを書きます。


<div class="h-16 flex items-center shadow-2xl">
    <img src="/storage/img/logo.png" alt="logo" class="w-1/4">
</div>

これがx-headerタグを使うことで読み込まれます。

そして最後にresource/views/welcome.blade.phpの中身をすべて消して、以下に書き換えます。


<x-app-layout>
    <router-view></router-view>
</x-app-layout>

x-app-layoutは先ほどのapp.blade.phpを読み込んでいます。
router-viewタグもとあるファイル(コンポーネント)を読み込んでいます。
これは後ほど設定するルーティングで決まるんですが、URLに応じたコンポーネントをここに入れ込むという具合です。

ここまでやると画像のように上にロゴがついたヘッダーが画面ができます。

ホーム画面用のVueコンポーネントを作成する

実際にページを作っていきます。
ここからはVueコンポーネントを作っていきます。概念はLaravelのコンポーネントと同じです。
resources/js/components/home/Index.Vueというファイルを作成します。

そして、ひな形として以下のコードを書きましょう。


<template>
//ここにhtml
</template>

<script>
export default {
    //ここにVue.js
}
</script>

templateタグの中にはhtmlを普通に書き込んでいけばOKです。
またscriptタグにはこのコンポーネントを内で適用する処理(関数)をJavascriptで書きます。

完成系は以下の通りです。


<template>
<div class="lg:container mx-auto md:px-4">
    <div class="md:flex items-center justify-center">
        <img src="/storage/img/header.png" alt="header" class="w-full md:w-3/4 max-w-2xl">
        <div>
            <p class="font-bold text-2xl lg:text-3xl text-center md:text-left">
                登録不要<br>
                サクッとアンケート作成
            </p>

            <div class="flex justify-center md:justify-start">
                <router-link :to="{name: 'form.create'}" class="inline-block my-3 bg-indigo-300 py-3 px-5 rounded-full text-white font-bold focus:outline-none hover:bg-indigo-200 duration-300">今すぐ作成する</router-link>
            </div>
        </div>
    </div>

    <div class="feature my-10">
        <h2 class="font-bold text-3xl text-center bg-indigo-200 py-2 rounded-md">3つの特徴</h2>
        <div class="sm:grid grid-cols-3 gap-4 my-5 mx-5">
            <div class="mb-20">
                <h3 class="font-bold text-xl text-center">ユーザー登録不要</h3>
                <div class="my-3">
                    <p class="sm:h-28 mb-5 sm:mb-0">登録、ログインなどの手間が省け今すぐ始めることができます。</p>
                    <img src="/storage/img/feature.png" alt="feature" class="w-48 sm:w-3/4 sm:h-3/4 m-auto  rounded-full">
                </div>
            </div>
            <div class="mb-20">
                <h3 class="font-bold text-xl text-center">素早く作成</h3>
                <div class="my-3">
                    <p class="sm:h-28 mb-5 sm:mb-0">シンプルなデザインで、タイトルと入力タイプを決めるだけで作れます。</p>
                    <img src="/storage/img/feature1.png" alt="feature1" class="w-48 sm:w-3/4 sm:h-3/4 m-auto  rounded-full">
                </div>
            </div>
            <div class="mb-20">
                <h3 class="font-bold text-xl text-center">スプレッドシートで管理</h3>
                <div class="my-3">
                    <p class="sm:h-28 mb-5 sm:mb-0">回答結果はGoogleスプレッドシートで自動で管理できます。</p>
                    <img src="/storage/img/feature2.png" alt="feature2" class="w-48 sm:w-3/4 sm:h-3/4 m-auto  rounded-full">
                </div>
            </div>
        </div>
    </div>

    <div class="guide my-5">
        <h2 class="font-bold text-3xl text-center bg-indigo-200 py-2 rounded-md mb-5">作成方法</h2>
        <div class="mx-5">
            <div class="guide-1 my-5 p-3 max-w-2xl mx-auto border-2 border-gray-300">
                <h3 class="font-bold text-lg sm:text-xl sm:text-center mb-3">アンケート作成画面で入力画面を作成</h3>
                <div class="sm:flex items-center justify-center">
                    <img src="/storage/img/guide0.png" alt="guide0" class="w-full max-w-md">
                    <p class="mt-5 md:mt-0">
                        タイトルと入力タイプを追加します。<br>
                        説明など細かい設定もできます。
                    </p>
                </div>
            </div>
            <img src="/storage/img/arrow.png" alt="arrow" class="w-60 m-auto">

            <div class="guide-2 my-5 p-3 max-w-2xl mx-auto border-2 border-gray-300">
                <h3 class="font-bold text-lg sm:text-xl sm:text-center mb-3">IDを取得</h3>
                <div class="flex items-center justify-center">
                    <p>
                        フォーム作成後にIDが自動で生成されます。<br>
                        IDをURLに設定することでリンクを作ることができます。<br>
                        *URLは「https://setform.site/form/生成されたID」です。
                    </p>
                </div>
            </div>
            <img src="/storage/img/arrow.png" alt="arrow" class="w-60 m-auto">

            <div class="guide-3 my-5 p-3 max-w-2xl mx-auto border-2 border-gray-300">
                <h3 class="font-bold text-lg sm:text-xl sm:text-center mb-3">スプレッドシートにコード貼りつけ</h3>
                <div class="flex items-center justify-center">
                    <p>
                        <a href="https://gist.github.com/24820c0aa19343d37aa636d671128dc0.git" class="underline ">「こちら」</a>のコードをGoogleスプレッドシートのスクリプトエディタに貼り付けます。
                    </p>
                </div>
            </div>
        </div>

        <div class="flex justify-center">
        <router-link :to="{name: 'form.create'}" class="inline-block my-3 mx-auto m-auto bg-indigo-300 py-3 px-5 rounded-full text-white font-bold focus:outline-none hover:bg-indigo-200 duration-300">さっそく作成</router-link>
        </div>

    </div>
</div>
</template>

<script>
export default {
    
}
</script>

tailwind cssを使っているのでクラスが分かりづらいかもしれませんが、詳しくはtailwind cssについて調べてみてください(僕のブログでも解説しますが)。

最初のトップページなのでscript内には特に記述は必要ないです。

ここでやっていること

ここでのポイントはrouter-linkというものです。
vue.jsにはrouterというものがあって、URLに応じてどのコンポーネントを読み込むかを設定できます。
Laravelが分かる方はweb.phpに当たるものです。
routerはこの後出てくるのですが、動的にaタグを生成することができるものです。

routerの設定

routerの設定をします。
resources/js/router.jsを作成します。説明はコードを書いてから説明します。


// vueおよびvue-routerの読み込み
import Vue from 'vue'
import VueRouter from 'vue-router';
Vue.use(VueRouter);

//コンポーネントの読み込み
import Index from './components/home/Index.vue'

//ルート設定
export default new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            name: 'home',
            component: Index
        },
    ]
})

ここでやっていること

重要なのはこの部分です。


    routes: [
        {
            path: '/',
            name: 'home',
            component: Index
        },
    ]

ここでルート設定を行っています。
ルートとは、「ooというURLを打ったらxxコンポーネントを読み込みますよ」というものです。
1つのルートごとに{}で追加していきます。

書き方はこんな感じ。


        {
            path: URLを設定,
            name: URLの代わりになる名前を設定,
            component: コンポーネントの名前
        },

これを設定すると「pathに設定したurlを入れたらcomponentに設定したコンポーネントを読み込む」ということになります。

ちなみにnameについては、例えばpath'/home/index'としてname'home'にすると、この'home'という名前を使ってURLを指定することができます。

nameを使うことで、途中でURLを変えたとしてもnameを変更しなければリンク切れなどが起きずに済むので便利です。

今回はこのように設定しました。


    routes: [
        {
            path: '/',
            name: 'home',
            component: Index
        },
    ]

つまり「http://example.com/にアクセスしたらIndex.Vueファイルを読み込む」ということになります。

そして、このファイルが最初に作ったLaravelコンポーネントapp.blade.php{{slot}}にハマるということになります。

Laravelのルート設定

最後です。
このプロジェクトではLaravelのルーティングは使いません(Vue.jsですべて処理するので。)
が、1つだけ設定をつけます。
routes/web.phpの中身で、コメント以降のコードをこのように書き換えてください。


Route::get('/{any}', function () {
    return view('welcome');
})->where('any', '.*');

これは、「どんなURLが入力されてもwelcome.blade.phpを読み込んでくださいね。」という命令をしています。

welcome.blade.phpはすべての起点となるファイルです。
というのも、このファイルの中にVueコンポーネントを入れ込むわけですから、どんなURLでもまずはこのファイルを読み込んで欲しいわけです。

ここまで、やるとホーム画面は完成です。

ふぅ、疲れました。ではでは、休んで次に行きましょう。

(随時更新)

スポンサードサーチ

オススメ英語学習用SNS "Our Dictionary"

人気記事英語学習用SNSをLaravelで作ってみた【システム解説あり】