Part 4. ページレイアウトの構造化


ここまでで ASP.NET MVC Core を使った簡単なページはできましたが、ちょっとダサいです;。なのでこれを jQuery や Bootstrap でちょっと綺麗にしてみます。

■ Bootstrap の利用

Bootstrap は非常に有名な CSS フレームワークのひとつで、これを利用することにより、レスポンシブ対応の Web サイトを比較的容易に構築していくことができます。Bootstrap については日本語でも多数の書籍が出ていますので、詳細についてはここでは書きません。先に作成した Index.cshtml ファイルの Web ページを、Bootstrap を使ってカッコよくしてみると、以下のようになります。

image

Index.cshtml ファイルのソースコードは以下の通りです。(かなり長いですが、大半は呪文です。要点はソースコードの後ろに書いてあります。)


@using Decode2016.WebApp.Models

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>de:code 2016</title>
    <meta name="viewport" content="width=device-width, intial-scale=1.0" />

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

    <style type="text/css">
        @@media only screen and (min-width : 768px) {
            html {
                position: relative;
                height: 100%;
            }
            body {
                height: 100%;
                padding-top: 50px;
                padding-bottom: 50px;
            }
            .contentWrapper {
                overflow: auto;
                height: 100%;
            }
            .contentBody {
                padding-top: 10px;
                padding-bottom: 10px;
                min-height: 100%;
            }
            .footer {
                position: fixed;
                bottom: 0;
                margin-bottom: 0;
                width: 100%;
                height: 50px;
                background-color: #f5f5f5;
            }
            .navbar-custom-responsive {
                position: fixed;
                width:100%;
                top:0px;
                border-width: 0 0 1px 0;
            }
        }
        @@media only screen and (min-width : 0px) {
            html {
            }
            body {
            }
            .contentWrapper {
            }
            .contentBody {
                padding-top: 10px;
                padding-bottom: 10px;
            }
            .footer {
                bottom: 0;
                margin-bottom: 0;
                width: 100%;
                height: 50px;
                background-color: #f5f5f5;
            }
            .navbar-custom-responsive {
                margin-bottom: 0;
            }
        }
    </style>

    <style type="text/css">
        div.row ul {
            padding-left: 30px;
        }
    </style>


</head>
<body>
    <nav class="navbar navbar-static-top navbar-default navbar-custom-responsive" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="/"><span class="glyphicon glyphicon-leaf"></span>&nbsp;&nbsp;de:code 2016</a>
                <button type="button" class="navbar-toggle" data-target="#navbar" data-toggle="collapse">
                    <span class="sr-only">ナビゲーションの表示</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div class="navbar-collapse collapse" id="navbar">
                <ul class="nav navbar-nav navbar-right">
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                            各種サンプル&nbsp;<span class="caret"></span>
                        </a>
                        <ul class="dropdown-menu">
                            <li><a href="/Sample01/FilterByStateWithSort">従来型の Web アプリ</a></li>
                            <li><a href="/Sample02/FilterByStateWithSort">SPA 型の Web アプリ</a></li>
                            <li><a href="/Sample03/FilterByState">jQuery + Bootstrap + knockout.js</a></li>
                            <li><a href="/Sample04/ListAuthors">非 SPA ベースでの実装</a></li>
                            <li><a href="/Sample05/ListAuthors">SPA ベースでの実装</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <div class="contentWrapper">
        <div class="container contentBody">

            @{
                var authors = (List<Author>)ViewData["Authors"];
            }
            <table class="table table-condensed table-striped table-hover">
                <thead>
                    <tr>
                        <th>著者ID</th>
                        <th>著者名</th>
                        <th>電話番号</th>
                        <th>契約有無</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var a in authors)
                    {
                        <tr>
                            <td>@a.AuthorId</td>
                            <td>@a.AuthorFirstName @a.AuthorLastName</td>
                            <td>@a.Phone</td>
                            <td>@(a.Contract ? "契約あり" : "契約なし")</td>
                        </tr>
                    }
                </tbody>
            </table>

        </div>
    </div>

    <footer class="footer">
        <div class="text-right" style="padding-top: 13px; padding-right: 20px; ">&copy; 2016 Microsoft Corporation. All rights reserved.</div>
    </footer>
</body>
</html>

ややこしいソースコードになっていますが、要点は以下の通りです。細かいコードはわからなくてもとりあえず構いません

  • Bootstrap は簡単のため、CDN 上で公開されているものをそのまま参照して利用しています。
  • ぐだぐた書かれているスタイルシート <style type=”text/css”> 部分は、ヘッダー・フッター部の制御のためのものです。
  • <body> 内は、ヘッダー部分+中身のコンテンツ部分+フッター部分の 3 ブロックで構成されています。
    • ヘッダー部分 <nav> は、Bootstrap の機能を使って作っています。これにより、ドロップダウンタイプのショートカットメニューを実現しています。(リンク先はとりあえずダミーですが)
    • <div class=”container contentBody”> 内が本体部分です。Part 3. の最後で作成したテーブルをここに移植してあります。(Bootstrap のデザインを適用するため、<table>タグに class=”table table-condensed table-striped table-hover” の指定をつけています。これによりきれいなデザインになります。)
    • フッター部分 <footer> は自力で作成しています。フッターの位置制御は、スタイルシートで行っています。

■ ページの構造化

さて、今回はまだ 1 つのページしか作っていませんが、実際の Web サイトでは複数の Web ページを作成するのがふつうで、しかもこれは下図のように共通のヘッダーやフッター、あるいはライブラリを使うのがふつうです。

image

上に示したように、個々のページは下図のようなレイアウトを持ちますが、共通部分を各ページの *.cshtml ファイルにコピペで貼り付けていたら、明らかにサイトのメンテナンス性は落ちます。

image

このため、実際の Web サイトでは、下図のように構造化を行い、① 共通 UI 部分などについてはレイアウトページに掃き出す、② 個々のページは差分だけ実装する、③ ページごとに組み込むか否かは異なるものの、よく使うものについては部品として用意しておく、ということを行います。

image

具体的には以下の作業を行います。

  • /Views/Shared フォルダを作成し、ここに _Layout.cshtml ファイルを作成する。
  • /Views/Home/Index.cshtml ファイルを、差分情報のみに変更する。

[/Views/Shread/_Layout.cshtml ファイル]

ポイントとなるのは以下の 5 箇所です。コードからわかるように、required:false になっているものは、指定してもしなくても OK になっています。

  • @ViewData[“Title”] : ページタイトルを個別ページ側から指定できるようにするためのもの
  • @RenderSection(“Libraries”, required: false) : 標準的に組み込まれている、Bootstrap, jQuery 以外のライブラリを個々のページで組み込む際に利用
  • @RenderSection(“Styles”, required: false) : 個々のページで追加の CSS 指定をしたい場合に利用
  • @RenderBody() : 本体部分を埋め込み
  • @RenderSection(“Scripts”, required: false) : 個々のページの JavaScript を指定

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewData["Title"]</title>
    <meta name="viewport" content="width=device-width, intial-scale=1.0" />

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

    @RenderSection("Libraries", required: false)

    <style type="text/css">
        @@media only screen and (min-width : 768px) {
            html {
                position: relative;
                height: 100%;
            }

            body {
                height: 100%;
                padding-top: 50px;
                padding-bottom: 50px;
            }

            .contentWrapper {
                overflow: auto;
                height: 100%;
            }

            .contentBody {
                padding-top: 10px;
                padding-bottom: 10px;
                min-height: 100%;
            }

            .footer {
                position: fixed;
                bottom: 0;
                margin-bottom: 0;
                width: 100%;
                height: 50px;
                background-color: #f5f5f5;
            }

            .navbar-custom-responsive {
                position: fixed;
                width: 100%;
                top: 0px;
                border-width: 0 0 1px 0;
            }
        }

        @@media only screen and (min-width : 0px) {
            html {
            }

            body {
            }

            .contentWrapper {
            }

            .contentBody {
                padding-top: 10px;
                padding-bottom: 10px;
            }

            .footer {
                bottom: 0;
                margin-bottom: 0;
                width: 100%;
                height: 50px;
                background-color: #f5f5f5;
            }

            .navbar-custom-responsive {
                margin-bottom: 0;
            }
        }
    </style>

    @RenderSection("Styles", required: false)

</head>
<body>
    <nav class="navbar navbar-static-top navbar-default navbar-custom-responsive" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="/"><span class="glyphicon glyphicon-leaf"></span>&nbsp;&nbsp;de:code 2016</a>
                <button type="button" class="navbar-toggle" data-target="#navbar" data-toggle="collapse">
                    <span class="sr-only">ナビゲーションの表示</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div class="navbar-collapse collapse" id="navbar">
                <ul class="nav navbar-nav navbar-right">
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                            各種サンプル&nbsp;<span class="caret"></span>
                        </a>
                        <ul class="dropdown-menu">
                            <li><a href="/Sample01/FilterByStateWithSort">従来型の Web アプリ</a></li>
                            <li><a href="/Sample02/FilterByStateWithSort">SPA 型の Web アプリ</a></li>
                            <li><a href="/Sample03/FilterByState">jQuery + Bootstrap + knockout.js</a></li>
                            <li><a href="/Sample04/ListAuthors">非 SPA ベースでの実装</a></li>
                            <li><a href="/Sample05/ListAuthors">SPA ベースでの実装</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <div class="contentWrapper">
        <div class="container contentBody">

            @RenderBody()

        </div>
    </div>

    <footer class="footer">
        <div class="text-right" style="padding-top: 13px; padding-right: 20px; ">&copy; 2016 Microsoft Corporation. All rights reserved.</div>
    </footer>

    @RenderSection("Scripts", required: false)

</body>
</html>

[/Views/Home/Index.cshtml ファイル]

こちらは差分情報だけ残せばよくなるので、以下のコードのみで済むようになります。


@using Decode2016.WebApp.Models
@{ 
    Layout = "_Layout";
    ViewData["Title"] = "著者データ一覧";
}

@{
    var authors = (List<Author>)ViewData["Authors"];
}
<table class="table table-condensed table-striped table-hover">
    <thead>
        <tr>
            <th>著者ID</th>
            <th>著者名</th>
            <th>電話番号</th>
            <th>契約有無</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var a in authors)
        {
            <tr>
                <td>@a.AuthorId</td>
                <td>@a.AuthorFirstName @a.AuthorLastName</td>
                <td>@a.Phone</td>
                <td>@(a.Contract ? "契約あり" : "契約なし")</td>
            </tr>
        }
    </tbody>
</table>

上記のように修正して実行しても、全く動作結果が変わらないことを確認していただければと思います。

■ 共通レイアウトの強制

上記のサンプルで、Layout=”_Layout”; というコードがありますが、これはレイアウトページを指定するためのコードです。このコードをいちいち個別に指定していると面倒、ということもあると思います。このような場合には、/Views/_ViewStart.cshtml ファイルを追加し、そこに以下のように記述してください。これで個々のページでのレイアウトページ指定は不要になります。


@{
    Layout = "_Layout";
}

image

以上で ASP.NET MVC Core の Web アプリの骨格ができあがりました。引き続き、ASP.NET MVC Core を使った SPA 型 Web アプリ開発の基礎を説明していきます。


Comments (0)

Skip to main content