この記事は、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>© 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 を使ってみる (インデックス)
「ASP.NET MVC 3 で jQuery Mobile を使ってみる(その5)」への1件のフィードバック