Tải bản đầy đủ (.pdf) (19 trang)

10 chuong 10 tủ tài liệu bách khoa

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (927.35 KB, 19 trang )

CHAPTER10

SportsStore:Mobile
Không thể trốn tránh sự phổ biến của các thiết bị như smartphone hoặc tablet.Nếu bạn muốn truyền ứng dụng của mình đến với
nhiều người tiêu dùng nhất có thể, bạn sẽ phải chú trọng vào thế giới của các web browser trên di động. Nếu nghe có vẻ không
thích thú lắm, đó là bởi vì cụm từ Mobile web browser liên tưởng đến từ nhanh chóng, khả năng và là những trình duyệt hiện đại
có thể là đối thủ cạnh tranh với trình duyệt desktop nhưng lại thành ra chậm chạp, không phù hợp và lỗi thời
Tóm lại là gửi truyền tải trải nghiệm tốt đến nguoi dùng thiết bị di động là rất khó, khó hơn nhiều so với việc truyền nội dung
đến desktop. Nó cần lên kế hoạch cẩn thận, thiết kế mà nỗ lực kiểm thử rất lớn và cũng dễ bị phát hiện bởi những thiết bị
smartphone hay tablet đời mới

Putting Mobile Web Development inContext
(Đặt vấn đề về việc phát triển ứng dụng Web Mobile)
MVC Framework có những tính năng giúp việc phát triển trên modile nhưng MVC Framework lại là một server-side Framework
nhằm mục đích nhận các HTTP request và hồi đáp bằng HTML. Điều này có những hạn chế khi nó đối mặt với những những yêu
cầu tính năng chúng ta gặp phải khi nhắm đến đối tượng khách hàng sử dụng thiết bị di động.Mức độ mà MVC Framework có thể
hỗ trợ phụ thuộc vào chiến lược di động động mà bạn dự định. Có 3 chiến lược cơ bản về web mobile bạn có thể tuân theo. Chúng
ta sẽ đề cập nó trong những phần tiếp theo đây
Ghi chú: Có lựa chọn thứ 4 đó là tạo 1 ứng dụng gốc, nhưng chúng ta sẽ không bàn về nó vì không hề liên quan trực tiếp đến MVC
Framework hay ứng dụng web

Không làm gì cả (hoặc làm ít nhất có thể)
Nó có vẻ là một ý tưởng kỳ lạ khi không làm gì cả, thế nhưng một số thiết bị mobile có khả năng xử lý nội dung vốn được
phát triển dành cho các desktop client.Nhiều thiết bị được công bố gần đây có độ phân giải và độ hiển thị cao với bộ browser
có bộ nhớ lớn có thể dựng HTML và chạy Javascript một cách nhanh chóng.Nếu ứng dụng của bạn không đòi hỏi quá nhiều,
bạn có thể nhận ra rằng các thiết bị mobile sẽ không gặp phải quá nhiều vấn đề khi hiển thị nội dung ứng dụng của bạn. Một ví
dụ trong hình 10-1 cho thấy Ipad hiển thị ứng dụng SportsStore mà không hề phải chỉnh sửa

1



Figure 10-1.Displaying the SportsStore application on atablet

Nó thực hiện công việc khá tốt. Vấn đề duy nhất gặp phải đó là vùng link phân trang bị đẩy xuống dưới đáy của trang, điều
này có thể dễ dàng điều chỉnh bằng cách thay đổi số lượng sản phẩm được hiên thị trên một trang
Chú ý: Hình ảnh chúng ta thấy trong chương này đều được lấy từ Browserstack.com, đây là một dịch vụ kiểm thử browser đa
nền tảng chúng ta sử dụng để kiểm thử các project của mình. Nó không hẳn là dịch vụ hoàn hảo.Đôi khi nó chậm chạp và có thể
phân mảnh khi sử dụng ngoài lãnh thổ US, thiết bị mobile được giả lập.Chúng tôi sử dụng nó để hỗ trợ các browser trên
desktop, nó hoạt động mạnh hơn nhưng chúng ta lại nhận được kết quả như ý và chúng ta không cần phải bảo trì các bộ giả lập.
Các bạn có thể nhận bản dùng thử miễn phí theo ví dụ trong chương này và nó cũng có nhiều đối thủ cạnh tranh nếu như chúng
ta muốn có thêm những lựa chọn khác. Ghi nhớ rằng chúng tôi không hề có mối quan hệ nào với Browser stack, chúng tôi chỉ là
những khách hàng bình thường, vốn chi trả đầy đủ tiền cho sản phẩm và không hề nhận lấy bất kỳ sự quan tâm đặc biệt nào

Sử dụng thiết kế có tính tương tác (Responsive Design)
Hướng đi tiếp theo đó là tạo nội dung tương thích với khả năng của thiết bị sẽ hiển thị nó, được gọi là responsive design. Chuẩn
CSS có những tính năng cho phép chúng ta thay đổi thuộc tính của các element dựa vào khả năng của thiết bị, một kỹ thuật
được sử dụng nhiều nhất là thay đổi cấu trúc layout của nội dung dựa vào độ rộng của màn hình hiển thị
Responsive design là thiết kế được xử lý bởi phía client dùng CSS và không trực tiếp được quản lý bởi MVC Framework.Chúng
2


ta đi sâu vào chủ đề responsive design trong cuốn sách Pro ASP.NET MVC Client book. Tuy nhiên để chứng minh cách kỹ
thuật này được áp dụng (và một số điều cân nhắc có liên quan đến MVC Framework), chúng ta sẽ sử dụng một số tính năng của
thiết kế bao gồm thư viện Bootstrap vốn được sử dụng xây dựng giao diện cho ứng dụng SportStore (nó cũng trở thành một
trong số những giao diện MS tích hợp vào trong MVC 5 project cho Visual Studio 2013)
Mục tiêu của chúng là là điều chỉnh giao diện phần nội dung chính của ứng dụng cho phép nó hiển thị trên iPhone. Chiến lược
“không làm gì cả” của chúng ta không đáp ứng được trên thiết bị này do màn hình hiển thị hẹp hình 10-2

Figure 10-2.Displaying the SportsStore application on asmartphone

Chúng ta sẽ đối mặt với vấn đề này theo từng vùng, tập trung vào những khía cạnh khác nhau của layout. Mục tiêu là duy trì

được tất cả các tính năng của ứng dụng nhưng biểu diễn nó theo một cách khác
Ghi chú: MVC Framework không tham gia vào trong responsive design, nó chỉ gửi cho browser cùng một nội dung và để nó tự
xác định những bit nào sẽ được hiển thị. Điều này đồng nghĩa với không có cách nào để thêm unit test cho repsonsive design
trong Visual Studio. Đây là một kỹ thuật đòi hỏi sự cẩn thận trong khâu kiểm thử từ phía client và khó để tự động hóa

Tạo một Responsive Header
Chúng ta sẽ bắt đầu với phần header của trang web, bao gồm tên của SportsStore, thông tin chung của giỏ hàng và nút Checkout.
Mặc dù giả pháp đơn giản nhất là loại bỏ phần tên SportsStore và giải phóng không gian cho các nội dung khác tuy nhiên chúng
tôi vẫn giữ lại phần này (xem lại phần Accepting the realities of Branding (Chấp nhận sự có mặt của nhãn hiệu) sidebar) và sắp
xếm lại những nội dung khác thành 2 hàng

ACCEPTING THE REALITIES OFBRANDING
(Chấp nhận sự hiện diện của nhãn hiệu)
Một trong những cách đơn giản nhất để giải phóng không gian màn hình là loại bỏ thương hiệu của bạn khỏi ứng dụng.
Chúng ta chỉ cần biểu diện tên SportsStore dưới dạng text nhung chúng ta vẫn thấy được diện tích màn hình mà nó chiếm
dụng . Nhãn hiệu vốn khiêm tốn trên màn hình desktop thì nay trở thành một thứ chiếm dụng không gian trên smartphone
One of the easiest ways to free up screen real-estate is to remove your branding from the application. I am only displaying the
SportsStore name as text, but you can see how much of the screen it occupies. What was a modest degree of branding on
the desktop becomes a space hog on a smart phone.
3


Loại bỏ nhãn hiệu vốn rất khó, tuy nhiên. Không phải vì lý do kỹ thuật nhưng những nhóm phát triểu thương hiệu bị ám ảnh
bởi việc đặt thương hiệu lên mọi thứ.Đây là lí do các chúng ta thấy những cây bút có in thương hiệu công ti trong phòng
họp, ly tách ở phòng nghỉ và cũng là lí do bạn phải làm mới business card của mình sau mỗi 18 tháng với logo mới. Việc
thay đổi nhãn hiệu thương xuyên vì những người làm thiết kế thương hiệu biết rằng, sâu bên trong, họ không có một công
việc thực sự và việc liên tục tập trung vào logoc và mảng màu sắc tạo nên một hoạt động điên cuồng, khiến họ phân tâm
khỏi nỗi sợ hãi tồn tại ám ảnh họ mỗi khi thức dậy
Lời khuyên là chấp nhận một khoảng trên màn hình dành cho nhãn hiệu, dù cho đó có là thiết bị nhỏ nhất. Bạn có thể phản đối ý
tưởng này nhưng nhóm phát triển thương hiệu thường là một phần trong bộ phận marketing, marketing thương báo cáo về VP ở

bộ phận sale và VP có mối quan hệ mật thiết với CEO vì lợi tức thu về là tất cả những gì họ quan tâm. Vì thế đây là cuộc tranh
luận mà chúng ta không thế chiến thắng
Trong hình 10-1, chúng ta có thể thấy nội dung của header đã được điều chỉnh trong Layout.cshtml trong project
SportsStore.WebUI
Listing 10-1.Adding Responsive Content to the _Layout.cshtmlFile

<!DOCTYPEhtml>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link href="∼/Content/bootstrap.css" rel="stylesheet"/>
<link href="∼/Content/bootstrap-theme.css" rel="stylesheet"/>
<link href="∼/Content/ErrorStyles.css" rel="stylesheet"/>
<title>@ViewBag.Title</title>
<style>
.navbar-right{
float: right!important;
margin-right: 15px; margin-left:15px;
}
</style>
</head>
<body>
<div class="navbarnavbar-inverse">
<a class="navbar-brand"href="#">
<span class="hidden-xs">SPORTSSTORE</span>
<divclass="visible-xs">SPORTS</div>
<divclass="visible-xs">STORE</div>
</a>
@Html.Action("Summary","Cart")

</div>
<div class="rowpanel">
<div id="categories"class="col-xs-3">
@Html.Action("Menu","Nav")
</div>
<divclass="col-xs-8">
@RenderBody()
</div>
</div>
</body>
</html>

4


Bootsrap định nghĩa 1 bộ các lớp có thể được sử dụng để ẩn đi các element dựa theo độ rộng của màn hình thiết bị. Bạn có thể
điều chỉnh nội dung này bằng cách sử dụng các câu lệnh truy vấn CSS media, nhưng các lớp Bootstrap được tích hợp vào trong
các thuộc tính styles khác
Về phần nhãn hiệu SportsStore chúng ta sử dụng lớp visible-xs và hidden-xs để chuyển thành dạng text chia thành 2 hàng và
được biểu diễn theo chiều dọc khi kích thước màn hình bé hơn 768 pixels. Bootstrap cung cấp những cặp các lớp cho phép hiển
thị và giấu đi các elements trên các browser có kích thước màn hình khác nhau, tên của chúng bắt đầu bằng visible- hoặc hidden.Phần đuôi của các lớp “**-xs” (ví dụ visible-xs và hidden-xs) được dùng trong ví dụ trên. Phần *-sm trong các lớp chạy trên
phần màn hình lớn hơn 768 pixel, phần *-md chạy trên phần màn hình lớn hơn 992 pixel và đuôi –lg chạy trên màn hình lớn hơn
1200 pixel
Chúý: tính năng Responsive CSS cũng giống tính năng mà Bootstrap cung cấp dựa trên độ lớn của màn hình browser, không phải
màn hình thiết bị. Browser trên thiết bị di động thường hiển thị toàn màn hình, nghĩa là kích thước màn hình và kích thước cửa sổ
của browser là bằng nhau.Chúng ta không phải lúc nào cũng dựa trên trường hợp này. Như mọi khi, chúng ta cần kiểm thử trên thiết
bị mà chúng ta nhắm tới để đảm bảo rằng chúng ta không vướng phải một trường hợp giảđịnh có thể bị phát hiện
Caution Responsive CSS features like the ones that Bootstrap provide are based on the size of the browser window, not the
device screen. Mobile device browsers are usually displayed full-screen, which means that the window size and the screen size are
the same, but you can’t always rely on this being the case. As ever, you need to test against the devices you are targeting to

ensure that you have not made assumptions that catch you out.
Chúng ta có thể thấy hiệu ứng đã thay đổi khi khởi động ứng dụng và xem danh sách sản phẩm trên một desktop browser thông thường,
vốn có ưu điểm cho phép chúng ta thay đổi kích thước cửa sổ. Điều chỉnh của sổ nhỏ lại (bé hơn 786 pixels) chúng ta có thể thấy dòng chữ
SportsStore được đẩy thành 2 dòng như trong hình 10-3

Figure 10-3.Using Bootstrap responsive design features to adjust the applicationbranding

Đây có vẻ chỉ là một thay đổi nhỏ nhưng nó có tác động lớn đối vối màn hình khoo3 đặc biệt khi kết hợp với thay đổi chúng
ta tạo ra trong file Views/Cart/Summary.cshtml. Đây là view cung cấp tóm tắt về giỏ hàng và nội dung của nó. Chúng ta có thể
thấy những thay đổi trong hình 10-2
Listing 10-2.Thêm nội dung Responsive vào file Summary.cshtml
Adding Responsive Content to the Summary.cshtml File

@modelSportsStore.Domain.Entities.Cart
<div class="navbar-righthidden-xs">
@Html.ActionLink("Checkout", "Index", "Cart",
new { returnUrl = Request.Url.PathAndQuery },
new { @class = "btn btn-default navbar-btn"})
</div>
<div class="navbar-rightvisible-xs">
href=@Url.Action("Index",
Request.Url.PathAndQuery})
class="btn btn-defaultnavbar-btn">
5

"Cart",

new


{

returnUrl

=


<span class="glyphiconglyphicon-shopping-cart"></span>
</a>
</div>
<div class="navbar-textnavbar-right">
<b class="hidden-xs">Yourcart:</b>
@Model.Lines.Sum(x =>x.Quantity)item(s),
@Model.ComputeTotalValue().ToString("c")
</div>
Trên đây sử dụng cùng 1 kỹ thuật áp dụng để giấu và hiện nội dung đối với với file _Layout.cshtml. Trong trường hợp này,
chúng ta giấu đi phần nút Checkout now chuẩn và thay bằng một nút icon, sử dụng 1 trong số những icon trong Bootstrap
package
Bootstrap icon được đặt vào dùng <span> element, nghĩa là chúng là không thể dùng công cụ Html.ActionLink helper vì nó
không cung cấp khả năng đặt nội dung vào trong element nó tạo ra. Thay vào đó chúng ta định nghĩa <a> element trực tiếp sử
dụng công cụ trợ giúp Url.Action (miêu tả trong chương 23).Để khởi tạo một URL cho thuộc tính href.Câu trả lời là <a> element
với cùng thuộc tính sẽ được tạo vởi Html.ActionLink nhưng bao gồm một <span> slement. Chúng ta có thể thấy thay đội trong
file ở hình 10-4, biểu diễn nội dung header trên iPhone

Figure 10-4.The modified SportsStore header displayed on an iPhonesimulator

MOBILE FIRST VERSUS DESKTOPFIRST
Hầu hết dự án web project bắt đầu với desktop slient sau đó sẽ hỗ trợ cho mobile client, tương tự như những gì chúng ta
đang thực hiện trong sách. Đây gọi là thiết kế phát triển theo hướng desktop first và vấn đề nằm ở việc phát triển phía
server cần hoàn thiện rất nhiều trước khi phát triển cho mobile client, kết quả là trải nghiệm trên mobile trở nên gượng gạo

và mất đi nhiều tính năng vốn có thể sử dụng trên desktop client
Có một triết lý thanh thế gọi là phát triển theo hướng Mobile first có nghĩa là theo như tên gọi, phát triển cho mobile client
làm nền tảng cho ứng dụng và thêm mới tính năng tận dụng khả năng của desktop browser
Hoặc nói một cách khác, desktop first có xu hướng bắt đầu với bộ tính năng đầy đủ sau đó sẽ giảm bớt cho các thiết bị với khả
năng kém hơn trong khi mobile first là xu hướng bắt đầu với một bộ tính năng ít hơn và được nâng cấp lên cho các thiết bị với
khả năng đáp ứng tốt hơn
Cả hai hướng tiếp cận đều có những tích cực, riêng tôi thường thích hướng desktop fist hơn vì nó dễ dàng để các desktop browser
lấy nội dung từ ngay trong môi trường làm việc.Điều này lại cực kỳ khó khăn đôi với thiết bị mobile. Tôi có xu hướng làm trong
một vòng tròn chặt chẽ của việc viết, biên dịch và kiếm tra, nghĩa là reload lại các đường dẫn URL liên tục, điều này lại khiến tôi
khổ sở khi áp vào cùng một vòng làm việc ấy khi phát triển theo hướng mobile first trên thiết bị mobile
Sự nguy hiểm khi đặt 1 nhóm người dùng nào lên trước tạo ra một trải nghiệm kém chất lượng đối với nhóm kia, và cứ thế.
Những người ủng hộ xu hướng mobile first thường tranh cãi rằng điều này là không thể khi chúng ta bắt đầu với những
tính năng cơ bản và đẩy nó lên, điều này tôi (tác giả) vẫn chưa trải nghiệm
The danger in putting any group of users first is that you create a substandard experience for another group, just moving the
pain around. Proponents of mobile first design often argue that this can’t happen when you start with the basic features and
6


then scale up, but that has not been my experience.
Điều quan trọng là cần có một kế hoạch chắc chắn cho các tính năng mà layout của chúng ta sẽ truyền tải đến tất cả các
thiệt bị trước khi bắt đầu phát triển bất kỳ loại nào. Khi chúng ta đã có được một kế hoạch như thế, không quan trọng
thiết bị nào sẽ được bắt đầu trước và đặc biệt, phần bên phía server của ứng dụng sẽ được xây dựng trên cơ sở phục vụ
tất cả đối tượng client

Creating a Responsive ProductList
(Tạo một danh sách sản phẩm Responsive)
Để hoàn tất việc tương thích responsive, chúng ta cần 1 danh sách các sản phẩn được liệt kệ trên các thiết bị có màn hình
hiển thị hẹp. Vấn đề lớn nhất là không gian bề ngang chiếm dụng bởi nút category.Chúng ta sẽ chuyển nút này đi chỗ khác,
cho từng phần mô tả sản phẩm chiếm toàn bộ bề ngang phần hiển thị. Hình 10 -3, chúng ta có thể thấy tôi đã chỉnh sửa thêm
vào file _Layout.cshtml

Listing 10-3.Creating a Responsive Product List in the _Layout.cshtml File

<!DOCTYPEhtml>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link href="∼/Content/bootstrap.css" rel="stylesheet"/>
<link href="∼/Content/bootstrap-theme.css" rel="stylesheet"/>
<link href="∼/Content/ErrorStyles.css" rel="stylesheet"/>
<title>@ViewBag.Title</title>
<style>
.navbar-right{
float: right!important;
margin-right: 15px; margin-left:15px;
}
</style>
</head>
<body>
<div class="navbarnavbar-inverse">
<a class="navbar-brand"href="#">
<span class="hidden-xs">SPORTSSTORE</span>
<divclass="visible-xs">SPORTS</div>
<divclass="visible-xs">STORE</div>
</a>
@Html.Action("Summary","Cart")
</div>
<div class="rowpanel">
<div class="col-sm-3hidden-xs">
@Html.Action("Menu","Nav")

</div>
<div class="col-xs-12col-sm-8">
@RenderBody()
</div>
</div>
</body>
</html>
Chỉ có thể có 1 lời gọi đến hàm RenderBody trong layout này.Chúng ta sẽ đi vào chi tiết của layouts trong chương 20 nhưng
tác động của sự hạn chế này khiến chúng ta không thể có thêm các bộ element để giấu và hiện, mỗi bộ như thế đều cần lời gọi
đến RenderBody. Thay vào đó, chúng ta cần thanh đổi layout của lưới kèm theo lời gọi hàm RenderBody cho phép các element
trong layout tương thích với nội dung trong view
Một trong những lý do tôi sử dụng cấu trúc Bootstrap dáng lưới cho nội dung trong _Layout.cshtml ở chương 7 là nó bao gồm
7


các chức năng của thiết kế responsive cho phép làm việc với những hạm chế của RenderBody. Cấu trúc layout dạng lưới trong
Bootstrap hỗ trợ 12 cột và chúng ta xác định bao nhiêu element bằng cách đặt vào một class, như dưới đây, đây cũng là cách
chúng ta thiết lập các lớp Bootstrap trong chương 7

...
<div class="col-xs-8">
@RenderBody()
</div>
...
Cũng giống như hidden-* và visible-* được mô tả trước đây, Bootstrap cung cấp một bộ các lớp đặt số lượng column và trong
dạng lưới dựa theo bề rộng của cửa sổ
Các lớp col-xs-* được chỉnh sửa và không thay đổi theo bề rộng của màn hình hiển thị. Chúng ta sử dụng lớp col-xs-8 cho
Bootstrap biết element <div> nên được cách 1 khoảng bằng 8 trên 12 cột và hiển thị của element không đươc thay đổi theo bề
ngang cửa sổ. Nhóm lớp col-sm-* đặt các cột khi cửa sổ bằng 768 pixel hoặc rộng hơn.Lớp col-md-* làm việc với cửa sổ bằng 992
pixel hoặc rộng hơn và cuối cùng col-lg-* làm việc với cửa sổ có độ rộng bằng 1200 pixel hoặc rộng hơn. Lun phải chú ý về bề

rộng, đây là ví dụ các class chúng ta đặt vào element <div> xung quanh lời gọi tới hàm RenderBody. List 10-3

...
<div class="col-xs-12col-sm-8">
@RenderBody()
</div>
...

Kết quả của cả 2 class là <div> element sẽ chiến toàn bộ 12 cột trong lưới và 8 cột khi màn hình ở mức 768 px hoặc rộng
hơn. Những cột khác trong lưới bao gồm nút category như sau

...
<div class="col-sm-3 hidden-xs">
@Html.Action("Menu","Nav")
</div>
...
Element này sẽ chiếm 3 cột khi màn hình rộng hơn 768 pixel và được ẩn đi nếu đối với những trường hợp khác.Kết hợp với
các lớp khác chúng ta đưa vào, hiệu quả đạt được phần mô tả sản phẩm sẽ lấp đầy cửa sổ nhỏ và chia sẻ không gian với nút
bategory đối với cửa sổ lớn hơn.Chúng ta có thể thấy cả 2 layout trong hình 10-5. Tôi sử dụng desktop browser cho ví dụ nàu do
tôi có thể dễ dàng thay đổi bề rộng của cửa sổ

8


Figure 10-5.Using a responsive grid in the productlayout

9


Helping the Controller Select aView

(Giúp Controller chọn một View)
Tôi không muốn người dùng mobile bỏ qua khả năng lọc sản phẩm, nghĩa là chúng ta cần biểu diễn các category theo một hướng
khách. Để làm điều này, chúng ta tạo một view mới gọi là MenuHorizontal.cshtml trong Views/Nav folder với nội dung như trong
List 10-4
Listing 10-4. The Contents of the MenuHorizontal.cshtmlFile

@modelIEnumerable<string>
<div class="btn-group btn-group-smbtn-group-justified">
@Html.ActionLink("Home", "List", "Product", new { @class = "btn btndefault btn-sm"})
@foreach (var link in Model){
@Html.RouteLink(link, new {
controller = "Product",
action = "List",
category =link,
page=1
}, new{
@class = "btn btn-defaultbtn-sm"
+ (link == ViewBag.SelectedCategory ?" btn-primary" :"")
})
}
</div>
Đây là phiên bản thay đổi so với bản gốc Menu.cshtml layout nhưng với 1 vùng chứa dùng element <div> và một số lớp
Bootstrap để tạo layout bề ngang của các button. Chức năng cơ bản thì vẫn được giữ nguyên. Chúng ta tạo 1 nhóm các liên kết
lọc sản phẩm theo Category
Bộ các category button được tạo ra thông qua Menu action method của controller Nav, chúng ta cần update controller này để
nó có thể lựa chọn đến đúng file view dựa trên yêu cầu tập trung vào các nút bấm như trong List 10-5
Listing 10-5.Updating the Menu Action Method in the NavController.cs File

using System.Collections.Generic;
usingSystem.Web.Mvc;

using SportsStore.Domain.Abstract;
usingSystem.Linq;
namespace SportsStore.WebUI.Controllers {
public class NavController : Controller{
private IProductRepositoryrepository;
public NavController(IProductRepository repo) {
repository =repo;
}
public PartialViewResult Menu(string category = null,
bool horizontalLayout = false){
ViewBag.SelectedCategory = category;
IEnumerable<string> categories =repository.Products
10


.Select(x =>x.Category)
.Distinct()
.OrderBy(x =>x);
"Menu";
}
}
}
string viewName = horizontalLayout

? "MenuHorizontal"

: return

PartialView(viewName,categories)
Chúng ta định nghĩa một tham số mới cho action method xác định chiều, chúng ta dùng nó để chọn view file được truyền đến bởi

hàm PartialView. Để đặt giá trị cho tham số này, chúng ta cần quay lại file _Layout.cshtml như trong List 10-6
Listing 10-6.Updating the _Layout.cshtml File to Include the Horizontal Buttons

...
<body>
<div class="navbarnavbar-inverse">
<a class="navbar-brand"href="#">
<span class="hidden-xs">SPORTSSTORE</span>
<divclass="visible-xs">SPORTS</div>
<divclass="visible-xs">STORE</div>
</a>
@Html.Action("Summary","Cart")
</div>
<divclass="visible-xs">
@Html.Action("Menu", "Nav", new { horizontalLayout = true})
</div>
<div class="rowpanel">
<div class="col-sm-3hidden-xs">
@Html.Action("Menu","Nav")
</div>
<div class="col-xs-12col-sm-8">
@RenderBody()
</div>
</div>
</body>
...

11



Tham số không bắt buộc đến hàm html.Action là một object cho phép đặt giá trị cho hệ thống định tuyến, sẽ được đề cập trong
chương 15,16. Chúng ta sử dụng tính năng này để liên hệ xem controller nào nên được chọn. Kết quả tổng quát đạt được được thể
hình trong hình 10-6

Figure 10-6. The revised product listing for smallscreens

Chúng ta có thể thấy việc di chuyển nút lên trên cùng của danh sách sản phẩm tạo đủ khỏng trống cho mỗi sản phẩm có thể được hiển thị
một cách tương đối. Chúng ta có thể tiếp tục cải tiến để các view trở nên cân đối hơn tuy nhiên chúng ta cũng đã nắm được ý tưởng. Thay
vì diễn giải cụ thể về việc các lớp responsive trong CSS sẽ được sử dụng như thế nào, tôi muốn chạm đến những hạn chế trong MVC
Framework (ví dụ như hạn chế của hàm RenderBody )và một số các cơ sở có thể cung cấp nhầm hỗ trợ phát sinh nội dung theo các cách
khác nhau (ví dụ như như truyền dữ liệu từ View vào Controller thông qua hệ thống định hướng và hàm trợ giúp Html.Action )
Lưu ý. Chúng ta chỉ tập trung chủ yếu vào iPhone, đừng quên rằng thiết bị di động cho phép tập trung vào nhiều hướng và
chúng ta phải cung cấp đầy đủ cho chúng trong một project thực tế

Loại bỏ sự lặp lại của View
Trong ví dụ trước, tôi muốn cho bạn thấy chúng ta có thể khiến controller lựa chọn 1 view dựa trên vực định hướng thông tin
truyền đi bởi lời gọi từ hàm trợ giúp Html.Action. Đây là một tính năng quan trọng và hữu ích nhưng tôi muốn sử dụng nó
trong một project thực sự bởi vì nó đã để lại cho chúng ta 2 view bao gồm Menu.cshtml và MenuHorizontal.cshtml, nó chứa
những đoạn khai báo razor tương tự nhau. Đây là công đoạn bảo trì rủi ro vì bất kỳ thay đổi nào chúng ta yêu cầu nút lọc
category phải được đặt ở cả hai nơi. Để giải quyết vấn đề này chúng ta sẽ củng cố lại các view. Chúng ta tạo một view file
mới tên là FlexMenu.cshtml trong folder Views/Nav với nội dung như trong List 10-7
Listing 10-7. The Contents of the FlexMenu.cshtmlFile

@modelIEnumerable<string>
@{
boolhorizontal =((bool)(ViewContext.RouteData.Values["horizontalLayout"]
??false));
string wrapperClasses = horizontal ? "btn-group btn-group-sm btn-groupjustified" :null;
}
12



<divclass="@wrapperClasses">
@Html.ActionLink("Home", "List","Product",
new{@class=
horizontal ? "btnbtn-defaultbtn-sm":
"btn btn-block btn-defaultbtn-lg"
})
@foreach (var link in Model){
@Html.RouteLink(link, new {
controller = "Product",
action = "List",
category =link,
page=1
}, new{
@class = (horizontal ?"btnbtn-defaultbtn-sm"
: "btn btn-block btn-default btn-lg")
+ (link == ViewBag.SelectedCategory ?" btn-primary" :"")
})
}
</div>
Cái giá cho việc loại bỏ việc nhân bản các view là dùng 1 view phức tạp hơn có thể phát sinh ra cả 2 hướng tập trung của các
nút. Đây là vấn đề mang yếu tố cá nhân tùy theo bạn thích hướng tiếp cận nào hơn. Nếu như bạn giống tôi, tôi có xu hướng
tránh việc lặp lại , sau đó liệt kê một số tính năng bạn muốn thêm vào trong views
Đầu tiên là khả năng truy cập vào định tuyến thông tin trực tiếp từ view. Thuộc tính ViewContent cung cấp thông tin về trạng
thái hiện thời của yêu cầu đang được xử lý bao gồm cả chi tiết thông tin định tuyến như sau

...
boolhorizontal =((bool)(ViewContext.RouteData.Values["horizontalLayout"]
??false));

...
Tính năng thứ hai là khả năng tạo biến cục bộ bên trong view. Điều này là khả thi vì các mà Razor view được biện dịch thành
các class (sẽ được miêu tả trong Chương 20), và tôi tạo một biến cục bộ gọi là horizontal nghĩa là tôi không cân kiểm tra định
tuyến dữ liệu xuyên suốt danh sách để tìm ra hướng tập trung nào mà view đang được sử dụng
Chú ý các biến cục bộ nên được hạn chế sử dụng vì nó như một con dốc khi tạo các view khiến nó khó bảo trì và cũng
khó để kiểm thử, nhưng thỉnh thoảng chúng ta nên dùng trong những trường hợp như thế này khi mà nó là cái giá xứng
đáng cho việc đơn giản hóa một view
Một tính năng liên quan là các mà Razor thiết lập thuộc tính một các có điều kiện dựa vào các biến. Tôi định nghĩa một class
có tên gọi là kiểu string và có biến cục bộ trong view như sau

...
string wrapperClasses = horizontal
group- justified" :null;
...

? "btn-group

btn-group-sm btn-

Giá trị của biến wrapperClasses có thể là đoạn string của tên class mà tôi dùng cho layout theo chiều nang hoặc là null. Tôi
đặt biến này vào thuộc tính lớp như sau

...
<divclass="@wrapperClasses">
...
Khi biến là null, Razor đủ thông minh để loại bỏ hoàn toàn thuộc tính class trong element <div>, khởi tạo một element như sau

<div>
Khi mà biến đó không null, Rzor sẽ thêm vào giá trị và để nguyên thuộc tính class, cho ra kết quả như sau
13



<div class="btn-group btn-group-smbtn-group-justified">
Đây là một cách hay để nhóm các đặc tính của C# với mặt ý nghĩa của HTML như một tính năng vô cùng hữu ích khi viết
các view phức tạp bởi vì nó sẽ không thêm giá trị null vào thuộc tính và sẽ không phát sinh thuộc tính rỗng vốn có thể gây ra lỗi
với hàm chọn trong CSS (và một số thư viện Javascript dùng thuộc tính để chọn elements, cụ thể là jQuery)
Lưu ý: thuộc tính điều kiện sẽ hoạt động trên mọi biến, không những chỉ bao gồm những biến chúng ta định nghĩa trên view.
Điều này có nghĩa là chúng ta có thể sử dụng tính năng này đối với những thuộc tính trong model và viewbag
Để sử dụng view đã được củng cố, chúng ta cần xem lại Menu action method trong controller Nav như trong List 10-8
Listing 10-8.Updating the Menu Action in the NavController.cs File

...
public PartialViewResult Menu(string category = null){
ViewBag.SelectedCategory = category;
IEnumerable<string> categories =repository.Products
.Select(x =>x.Category)
.Distinct()
.OrderBy(x =>x);
return PartialView("FlexMenu",categories);
}
...

14


Tôi đã bỏ đi tham số nhận thông tin thay đổi hướng tập trung (orientation: hướng màn hình quay ngang hay dọc, trong này ám
chỉ hiện màn hình đang ở chế độ hoặc là ngang hoặc dọc)và thay đổi lời gọi đến PartialView method do đó FlexMenu luôn luôn
được chọn. Kết quả của các thay đổi đó không làm thay đổi layout của nội dung hay ảnh hưởng đến thiết kế responsive nhưng
nó hoàn toàn loại bỏ việc lặp các view và nghĩa là chúng ta có thể xóa Menu.cshtml và MenuHorizontal.cshtml view trong VS
project. Cả hai hướng tập trung của nút lọc category nay được tạo ra bởi FlexMenu.cshtml view


THE LIMITATIONS OF RESPONSIVEDESIGN
(Hạn chế của Responsive Design)
Có một số vấn đề đối với Responsive design đó là nó hỗ trợ tập trung quá nhiều vào mobile client. Đầu tiên chúng ta bị tình
trạng nhân bản quá nhiều nội dung và gửi nó đến server để có thể hiển thị trong những tình huống khác nhau. Chúng ta
thấy điều này trong phần trước khi HTML được phát sinh vởi layout có chứa nhiều bộ element dành cho phần header và
nút lọc category. Những elements mới thêm vào không ngốn quá nhiều trên mỗi lời gọi nhưng tổng quan, tác động cua nó
trên một ứng dụng đang ở mức busy là lớn khi mà nó làm tăng lượng băng thông chúng ta cần để cung cấp.dấn đến việc gia
tăng giá thành khi vận hành
Vấn đề thứ hai là responsive design có thể khó sử dụng và đòi hỏi nhiều công sức để kiểm thử để đạt kết quả mong đợi.
Không phải tất cả thiết bị cầm tay nào cũng có tính năng CSS cho phép responsive design (thường được biết đến như các
media queries) và nếu bạn không thật tỉ mỉ và cẩn trọng, bạn sẽ tạo ra một ứng dụng cung cấp trả nghiệm tương đương đối
vời từng thiết bị mà không xuất sắc trong đối với bất kỳ thiết bị nào, một kiểu hoạt động ở mức trung bình đối với mọi thiết
bị

Xây dựng nội dung cụ thể cho Mobile
Responsive design đưa đến cùng 1 nội dung trên mọi thiết bị sử dụng CSS để xem các thức bố trí nội dung. Công đoạn không liên
quan đến phần bên phía server-side của ứng dụng, nó giả định rằng chúng ta muốn xem tất cả các kiểu thiết bị theo một nền cơ
bản. Một hướng tiếp cận thay thế là dùng server để đánh giá khả năng của browser phía client và gửi các đoạn code HTML khác
nhau đến những người dùng khác nhau.Việc này khá tốt nếu chúng ta muốn thể hiện một khía cạnh hoàn toàn khác của ứng dụng
trên desktop hoặc trên tablet
Lưu ý: Chúng ta không cần chọn giữa responsive design và xây dựng nội dung cụ thể cho mobile. Trong hầu hết các project,
chúng ta cần phải sử dụng cả hai để đạt được kết quả tốt nhất trên đối tượng thiết bị mà chúng ta nhắm đến. Ví dụ chúng ta
có thể quyết định tạo một nội dung dành riêng cho tablet và dùng responsive design để tạo hướng ngang và dọc mà hầu hết
các tablet đều hỗ trợ
MVC framework hỗ trợ một tính năng gọi là display modes, cho phép tạo các views khác chuyển đến client dựa vào client đã
gửi đi yêu cầu, tính năng được cung cấp bởi ASP.NET Framework. Tôi giải thích cách chúng ta tạo và quản lý display modes
chuyên sâu trong cuốn Pro ASP.NET MVC 5 Platform nhưng nhằm mục đích phục vụ ứng dụng SportsStore, chúng tôi sẽ dùng
một form cơ bản nhất của display modes, nó sẽ đối xử với các thiết bị mobile tương tự nhau. Mục tiêu của tôi là chuyển trải
nghiệm người dùng đến thiết bị mobile dùng thư viện jQuery phổ biến cho Mobile, trong khi vẫn giữ nguyên nội dung đối với

thiết bị Desktop
Ghi chú, chúng ta sẽ không đi vào chi tiết jQuery Mobile trong cuốn sách này thay vì giải thích cách dùng nó để chuyển một
nội dung lên thiết bị di động cụ thể. Để biết thêm chi tiết về jQuery Mobile, tìm đọc Pro jQuery 2.0 của nhà xuất bản Apress

Creating a MobileLayout
(Tạo một Mobile Layout)
Tất cả những gì chúng ta cần là là tạo nội dung dành riêng cho thiết bị mobile để tạo các view và layout có hậu tố .Mobile.cshtml. Chúng ta tạo
một layout mới gọi là _Layout.Mobile.cshtml trong Views/Shared folder với nội dung như trong List 10-9
Chú ý: Bởi vì tên của View có thêm 1 dấu chấm, chúng ta sẽ cần tạo view bằng cách chuột phải Shared folder và chọn Add>MVC5 Layout Page
(Razor) trong cửa sổ pop-up

Listing 10-9. The Contents of the _Layout.Mobile.cshtml File

<!DOCTYPEhtml>
15


<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
href=" /><scriptsrc=" />src=" /><title>@ViewBag.Title</title>
</head>
<body>
<div data-role="page"id="page1">
<div data-theme="a" data-role="header"data-position="fixed">

SportsStore


@Html.Action("Menu","Nav")

</div>
<divdata-role="content">
<ul data-role="listview" data-divider-theme="b" datainset="false">
@RenderBody()
</ul>
</div>
</div>
</body>
</html>
Layout này sử dụng jQuery Mobile, chúng ta có thể lấy về thông qua content delivery network (CND), do đó chúng ta không
cần cài đặt cái gói NuGet cho JavaScript và CSS file mà chúng ta cần
Chú ý: Tôi chỉ vừa lướt qua phần nổi của việc tạo một view dành riêng cho mobile, bởi vì tôi dùng cùng 1 controller và action
method cho desktop client. Tách các view ra cho phép chúng ta giới thiệu các controllers khách nhau, giống như là dành riêng
cho 1 nhóm clients, nó có thể dùng để tạo một tính năng hoàn toàn mới và chức năng cho các đối tượng khách hàng khác nhau
MVC Framework sẽ tự động xác định mobile client và dùng file _Layout.Mobile.cshtml khi nó dựng các views, một cách kín
đáo thay thế _Layout.cshtml file vốn được dùng cho các client khác. Chúng ta có thể thấy tác động của sự thay đổi như trong
Hình 10-7

Figure 10-7.The effect of creating a mobile layout in the SportsStoreapplication

Chúng ta có thể thấy layout đã khác nhưng các hiệu ứng tổng quan còn lộn xộn đó là vì chúng ta cần tạo ra mobile version của view
16


chính sẽ xử lý các request và partial view được dùng cho nút lọc category

Tạo các Mobile Views
Chúng ta sẽ bắt đầu từ bộ lọc category, nghĩa là chúng ta sẽ tạo một view là FlexMenu.Mobile.cshtml trong Views/Nav folder
với nội dung như trong List 10-10
Listing 10-10. The Contents of the FlexMenu.Mobile.htmlFile


@modelIEnumerable<string>
<divdata-role="navbar">
<ul>
@foreach (var link in Model){
<li>
@Html.RouteLink(link, new {
controller = "Product",
action = "List",
category =link,
page=1
}, new{
data_transition ="fade",
@class = (link ==ViewBag.SelectedCategory
? "ui-btn-active" :null)
})
}
</ul>
</div>
</li>
View này dùng hàm Razor foreach để khởi tạo các <li> element cho product category, tạo ra các elements được sắp đặt theo
cách mà jQuery Mobile trông đợi cho một navigation bar nằm trên cùng của trang web. Chúng ta có thể thấy tác động như
trong hình 10-8

Figure 10-8. The effect of creating a mobile-specificview

Chú ý: jQuery Mobile phụ thuộc vào việc sử dụng dữ liệu thuộc tính để định dạng các elements. Thuộc tính dữ liệu được bắt
đầu với data- và là một cách không chính thức để định nghĩa thuộc tính trong nhiều năm trước khi trở thành một phần chính
thức của chuẩn HTML5. Trong danh sách, tôi cần thêm vào thuộc tính data-transition vào <li> element nhưng chúng ta không
thể dùng data-transition như thuộc tính tên cho anoymous object vì nó sẽ là một expression trong C#. Vấn đề ở đây là dấu

gạch (-) nối và Razor cùng làm việc bằng cách dịch dấu (_ )trong thuộc tính tên gọi thành dấu( - ) trong thuộc tính tên giống
như tôi có thể dùng data_transition trong danh sách và lấy thuộc tính data-transition trong các elements mà tôitạo
17


Thông tin product vẫn còn lộn xộn nhưng nút category đang được phát sinh bởi view dành riêng cho mobile. Việc này đáng
để bỏ ra 1 khoảng thời gian để phản ánh cách MVC Framework làm để dựng lên nội dung trong hình 10-8
HTTP request trong browser nhắm đến List action method trong Product controller, cho MVC biết để dựng List.cshtml file.
MVC Framework biết rằng request đến từ mobile browser nên nó sẽ tìm đến view dành riêng cho thiết bị mobile. Không có file
List.Mobile.cshtml nên List.cshtml file sẽ được xử lý thay vào đó.View này dựa vào file _Layout.cshtml nhưng MVC
Framework nhận ra có một phiên bản dành cho mobile nên nó sẽ dùng _Layout.Mobile.cshtml để thay thế. Layout yêu cầu file
FlexMobile.cshtml nhưng cũng có phiên bản mobile cho file này
Kết quả là phản hồi từ browser phát sinh từ cả view dành cho mobile lần view thông thườngMVC Framework dùng file view
cụ thể nhất có thể dùng nhưng lại bị giảm đi khi cần đến

THE TWO PROBLEMS IN THEEXAMPLE
2 vấn đề trong ví dụ
Ví dụ trong chương này được định ra để mô tả cách MVC Framework có thể truyền tải nội dung dành riêng cho mobile,
nhưng sẽ thật là thiếu sót nếu không chỉ ra 2 vấn đề rất nghiêm trọng ví dụ này có thể gây ra cho ứng dụng SportStore
Đầu tiên là chúng ta đã cung cấp ít tính năng hơn trên bất kỳ một thiết bị Mobile nào so với thiết bị Desktop,lấy ví dụ như
việc không hề có tổng hợp thông tin giỏ hàng trong phần header. Tôi đã bỏ bớt 1 số chức năng để đơn giản hơn cho những
thay đổi nhưng tôi khuyên không nên cung cấp bất kỳ sản phẩm nào đã lược bớt tính năng cho bất kỳ thiết bị nào trừ khi có
những hạn chế không cho phép thiết bị có thể hỗ trợ nó. Tiết bị Mobile ngày càng phổ biến đến người dùng và nhiều người
dùng chỉ truy cập vào ứng dụng bằng mobile browser. Chuyện ngày xưa khi bạn nghĩ mobile chỉ là thiết bị bổ sung cho
desktop đã không còn.
Vấn đề thứ hai là tôi đã không đưa ra khả năng cho phép user chuyển về desktop layout. Đứng đánh giá thấp số lượng
người dùng thích dùng desktop layout trên thiết bị mobile, dù cho nó có vẻ gượng gạo, kèm theo thao tác phóng to và cuộn
trên màn hình nhỏ. Một số thiết bị Mobile cho phép màn hình lớn hơn kết nối, điều này khó mà được nhận ra bởi cơ chế
của MVC Framework dùng để nhận diện thiết bị mobile. Chúng ta nên luôn cho phép người dùng mobile lựa chọn kiểu
layout họ muốn

Cả 2 vấn đề kể trên đều không ảnh hướng quá trình triển khai ứng dụng của chúng ta, nhưng nó là một sự thất bại đối với
người dùng ứng dụng trên thiết bị mobile. Thiết bị mobile sẽ là một phần quan trọng trong bất kỳ ứng dụng web hiện đại
nào và chúng ta nên lường trước để cung cấp trải nghiệm tốt đối với người dùng loại thiết bị này

Thay đổi cuối cùng của chúng ta là tạo ra phiên bản mobile phát sinh thông tin tổng quan product. Tôi tạo một view file gọi là
ProductSummary.Mobile.cshtml trong folder Views/Shared với nội dung như trong hình 10-11
Listing 10-11. The Contents of the ProductSummary.Mobile.cshtmlFile

@modelSportsStore.Domain.Entities.Product
data-role="collapsible"
data-collapsed="false"
datacontent- theme="c">


@Model.Name


<divclass="ui-grid-b">
<divclass="ui-block-a">
@Model.Description
</div>
<divclass="ui-block-b">
<strong>(@Model.Price.ToString("c"))</strong>
</div>
<divclass="ui-block-c">
@using (Html.BeginForm("AddToCart", "Cart")){
@Html.HiddenFor(x =>x.ProductID)
@Html.Hidden("returnUrl",Request.Url.PathAndQuery)
data-mini="true" value="Add to cart"/>
18



}
</div>
</div>
</div>

View này dùng jQuery Mobile widget cho phép user mở và tắt vùng nội dung. Đây không phải là cách lý tưởng để biểu diễn
thông tin product nhưng nó là cách đơn giản và nhấn mạnh đây là phần cho nội dung dành riêng cho mobile thay vì thư viện
jQuery Mobile. Chúng ta có thể thấy tác động trong 10-9

Figure 10-9. The effect of mobile-specificviews

Trong project thực tế, tôi sẽ còn phải tiếp tục, tạo ra phiên bản view dành riêng cho mobile hiển thị đường dẫn phân trang,
giỏ hàng và checkout form. Tuy nhiên chúng ta đã thấy cách MVC Framework cho phép chúng ta nhắm đến thiết bị mobile

Tổng hợp
Trong chương này chúng ta đã biết hai kỹ thuật để xử lý đối với thiết bị mobile: responsive design và nội dung dành riêng cho
mobile. Responsive Design không trực tiếp liên quan đến MVC Framework, nó sẽ gửi cùng 1 nội dung đến tất cả browser và
cho phép browser tự tìm cách xử lý nội dung đó. Nhưng như tôi đã nêu, có nhiều hạn chế trong cách views làm việc đòi hỏi
suy nghĩ cẩn thần và một số tính năng Razor cho phép giảm bớt quá trình xử lý
Tạo nội dung dành riêng cho mobile là tính năng MVC Framework cùng tham gia bằng cách tự đập áp view dành cho
mobile và layout nếu nó khả dụng và hòa trộn vào quá trình dừng lên HTML cho phía client. Trong chương tiếp theo chúng ta
sẽ thêm 1 số tính năng cần thiết để quẩn trị SportStore product catalog.

19




×