ASP.NET MVC 3 で jQuery Mobile を使ってみる(その5)

この記事は、jQuery Mobile を現時点の MVC 3 で使おうとするとどうなるかな、という興味から始めてみたものです。前回の記事でコントローラーについて書いた記事の続きになります。

静的コンテンツ

まず、Content フォルダの Site.css に notice-information クラスのスタイルを追加します。追加する場所はどこでも構いませんが、一番最後(editor and display helpers の一連のスタイル設定の後ろ)あたりが適当かもしれません。

/* Styles for notice-information
-----------------------------------------------------------*/
.notice-information {
  color: #ff0000;
}

次に、モバイル端末からのアクセス時のスタイル設定のために、Site.css をコピーして SiteMobile.css を作ります。jQuery Mobile が動的に設定するクラスなどのスタイルは jQuery Mobile の導入時にインストールされていますが、ASP.NET MVC のバリデーションのエラー通知とこのアプリ独自の通知メッセージ用のスタイルを設定する必要があります。「/* Styles for validation helpers」(バリデーションエラー表示関係用)と通知情報用のスタイル部分を残して、あとはばっさり削除します。

SiteMobile.css

/* Styles for validation helpers
-----------------------------------------------------------*/
.field-validation-error {
    color: #ff0000;
}

.field-validation-valid {
    display: none;
}

.input-validation-error {
    border: 1px solid #ff0000;
    /* background-color: #ffeeee; */
}

.validation-summary-errors {
    font-weight: bold;
    color: #ff0000;
}

.validation-summary-valid {
    display: none;
}

/* Styles for notice-information
-----------------------------------------------------------*/
.notice-information {
  color: #ff0000;
}

ビュー

ビューは、Shared フォルダの _Layout、Home フォルダの Index と About、そして Book フォルダのビューが対象です。
jQuery Mobile では、html コンテンツ中のタグの属性 data-role などを見て、動的に DOM ツリーを書き換えることでスマートフォンでの表示に適したページにしています(書き換えは jQuery Mobile が行うので、書き換えのための Javascript を書く必要はありません)。逆に言うと、「こういうレイアウト表示にするためには、属性に何を設定すればいいのか?」が分からないと何も出来ません 😉 jQuery Mobile の利用方法に詳しくない方は、次のサイトが分かりやすいと思うのでご覧ください。

Shared

_Layout.cshtml をコピーして _Layout.Mobile.cshtml を作り、jQuery Mobile で利用する Javascript ファイルと css ファイルへの参照を追加し、body 部のタグに data-role 属性を設定します。

_Layout.Mobile.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
  <meta name="viewport" content="width=device-width; initial-scale=1.0" />
  <link href="@Url.Content("~/Content/jquery.mobile-1.1.0.min.css")" rel="stylesheet" type="text/css" />
  <link href="@Url.Content("~/Content/SiteMobile.css")" rel="stylesheet" type="text/css" />
  <script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")" type="text/javascript"></script>
  <script src="@Url.Content("~/Scripts/jquery.mobile-1.1.0.min.js")" type="text/javascript"></script>
</head>
<body>
  <div data-role="page" data-theme="a" data-url="@ViewBag.DataUrl">
    <div data-role="header">
      <h1>テスト・サイト</h1>
      <div data-role="navbar">
        <ul>
          <li>@Html.ActionLink("ホーム", "Index", "Home")</li>
          <li>@Html.ActionLink("このサイトについて", "About", "Home")</li>
        </ul>
      </div>
    </div>

    <div data-role="content">
      @RenderBody()
    </div>

    <div data-role="footer">
      <h2>&copy; 2012 MakCraft</h2>
    </div>
  </div>
</body>
</html>

Home

Index.cshtml を修正した後、Index.cshtml と About.cshtml をコピーして Index.Mobile.cshtml と About.Mobile.cshtml を作成します。

Index.cshtml

@{
    ViewBag.Title = "ホーム";
}

<h2>@ViewBag.Message</h2>
<p>
    @Html.ActionLink("O'Reilly Japan から新刊・近刊情報を取得", "Index", "Book")します。
</p>

Index.Mobile.cshtml

@{
    ViewBag.Title = "ホーム";
    Layout = "~/Views/Shared/_Layout.Mobile.cshtml";
}

<h2>@ViewBag.Message</h2>
<p>
    @Html.ActionLink("O'Reilly Japan から新刊・近刊情報を取得", "Index", "Book")します。
</p>

About.Mobile.cshtml

@{
    ViewBag.Title = "このサイトについて";
    Layout = "~/Views/Shared/_Layout.Mobile.cshtml";
}

<h2>このサイトについて</h2>
<p>
     ここにコンテンツを置いてください。
</p>

Book

まず、普段と同様にコントローラーのアクションを右クリックして Index.cshtml、Details.cshtml、SendNotice.cshtml を作成してからレイアウトを調整します。その後、それぞれコピーして Index.Mobile.cshtml、Details.Mobile.cshtml、SendNotice.Mobile.cshtml を作成して jQuery Mobile 用にレイアウトを調整します。

Index.cshtml

@model IEnumerable<GetExternalXml001.Models.Book>

@{
    ViewBag.Title = "新刊一覧";
}

<h2>新刊一覧</h2>

@{
  if (TempData["message"] != null)
  {
    <div class="notice-information">通知情報: @Html.Encode(TempData["message"])</div>
  }
}


<table>
    <tr>
        <th>
            @Html.LabelFor(model => model.First().Title)
        </th>
        <th>
            @Html.LabelFor(model => model.First().Author)
        </th>
        <th>
            @Html.LabelFor(model => model.First().PublicationDay)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.ActionLink(@Html.Encode(item.Title), "Details", new {id=item.Id})
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Author)
        </td>
        <td>
            @Html.Encode(string.Format("{0:yyyy/MM/dd}", item.PublicationDay))
        </td>
        <td>
            @Html.ActionLink("概要を表示", "Details", new { id=item.Id })
        </td>
    </tr>
}

</table>

Index.Mobile.cshtml

@model IEnumerable<GetExternalXml001.Models.Book>

@{
    ViewBag.Title = "新刊一覧";
    Layout = "~/Views/Shared/_Layout.Mobile.cshtml";
}

<h2>新刊一覧</h2>

@{
  if (TempData["message"] != null)
  {
    <h4 style="color: Red">通知情報: @Html.Encode(TempData["message"])</h4>
  }
}

<ul data-role="listview" data-filter="true">
@foreach (var item in Model) {
    <li>
      <a href="@UrlHelper.GenerateUrl(null, "Details", null, new RouteValueDictionary(new {id=item.Id}),
        this.Html.RouteCollection, this.Html.ViewContext.RequestContext, true)">
        <h3>@Html.Encode(item.Title)</h3>
        <p>@Html.Encode(item.Author)</p>
        <p>刊行日: @Html.Encode(string.Format("{0:yyyy/MM/dd}", item.PublicationDay))</p>
      </a>
    </li>
}
</ul>

data-filter を設定することで、表示する一覧情報の絞込みの UI を実装しています。スマートフォンは画面が小さいので、こういう便利な機能の実装が楽なのはいいですね! 😉 画面例は「その1の記事」を御覧ください。

Details.cshtml

@model GetExternalXml001.Models.Book

@{
    ViewBag.Title = "新刊情報";
}

<h2>新刊情報</h2>

<fieldset>
    <legend>新刊の概要</legend>

    <div class="display-label">@Html.LabelFor(model => model.Title)</div>
    <div class="display-field">
        <a href="@Model.Link" target="_blank">@Html.Encode(Model.Title)</a>
    </div>

    <div class="display-label">@Html.LabelFor(model => model.Description)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Description)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.Author)</div>
    <div class="display-field">
        @Html.DisplayFor(model => model.Author)
    </div>

    <div class="display-label">@Html.LabelFor(model => model.PublicationDay)</div>
    <div class="display-field">
        @Html.Encode(String.Format("{0:yyyy/MM/dd}", Model.PublicationDay))
    </div>

</fieldset>

<div class="display-label">メール通知</div>
<div>@Html.ActionLink("この情報をメールで送信する", "SendNotice", new { id = Model.Id })</div>
<p>
    @Html.ActionLink("Back to List", "Index")
</p>

Details.Mobile.cshtml

@model GetExternalXml001.Models.Book

@{
    ViewBag.Title = "新刊情報";
    Layout = "~/Views/Shared/_Layout.Mobile.cshtml";
}

<h2>新刊情報</h2>

<h3>@Html.LabelFor(model => model.Title)</h3>
  <p><a href="@Model.Link">@Html.Encode(Model.Title)</a></p>
<h3>@Html.LabelFor(model => model.Description)</h3>
  <p>@Html.DisplayFor(model => model.Description)</p>
<h3>@Html.LabelFor(model => model.Author)</h3>
  <p>@Html.DisplayFor(model => model.Author)</p>
<h3>@Html.LabelFor(model => model.PublicationDay)</h3>
  <p>@Html.Encode(string.Format("{0:yyyy/MM/dd}", Model.PublicationDay))</p>
<h3>メール通知</h3>
  <p>@Html.ActionLink("この情報をメールで送信する", "SendNotice", new { id = Model.Id })</p>

SendNotice.cshtml

@model GetExternalXml001.Models.NoticeInfo

@{
    ViewBag.Title = "新刊情報のメール送信";
}

<h2>新刊情報のメール送信</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>メール送信情報の設定</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.MailAddress)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MailAddress)
            @Html.ValidationMessageFor(model => model.MailAddress)
        </div>

        @Html.HiddenFor(model => model.Title)
        @Html.HiddenFor(model => model.Url)

        <p>
            <input type="submit" value="メールで送信" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("一覧へ戻る", "Index")
</div>

SendNotice.Mobile.cshtml

@model GetExternalXml001.Models.NoticeInfo

@{
    ViewBag.Title = "新刊情報のメール送信";
    Layout = "~/Views/Shared/_Layout.Mobile.cshtml";
}

<h2>新刊情報のメール送信</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <div data-role="fieldcontain">
        <fieldset data-role="controlgroup">
            <legend>メール送信情報の設定</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.MailAddress)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MailAddress)
            @Html.ValidationMessageFor(model => model.MailAddress)
        </div>

            @Html.HiddenFor(model => model.Title)
            @Html.HiddenFor(model => model.Url)

            <p>
                <input type="submit" value="メールで送信" />
            </p>
        </fieldset>
    </div>
}

<div>
    @Html.ActionLink("一覧へ戻る", "Index")
</div>

以上で新刊一覧を表示するアプリが完成(してるはず)です 🙂

MVC 3 でもわりかし楽にスマートフォン用のビューとの切り替えができますね。MVC 4 だと切り替えをフレームワーク側でやってくれるみたいなので、更に楽になりますね!なんか一つの HTML コンテンツ中で表示ページの切り替えというような文言もあったみたいだし、jQuery Mobile のページ切り替えにも対応したものができるかも。。。という期待も 😀


ASP.NET MVC 3 で jQuery Mobile を使ってみる (インデックス)


1 thought on “ASP.NET MVC 3 で jQuery Mobile を使ってみる(その5)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です