快速入門系列--MVC--07與HTML5移動開發的結合


    現在移動互聯網的盛行,跨平台並兼容不同設備的HTML5越來越盛行,很多公司都在將自己過去的非HTML5網站應用漸進式的轉化為HTML5應用,使得一套代碼可以兼容不同的物理終端設備和瀏覽器,極大的提高了系統的可維護性和可擴展性。於此同時,HTML5提供了很多的新特性,比如新的架構元素、代替cookie的Web存儲技術、WebSocket等,也使得網站應用能夠更好適應新的商業環境和技術更新。

    本系統的網站模塊使用.NET技術堆棧中的ASP.NET MVC框架,此框架是微軟公司推出的開源框架,相關源代碼可以在Codeplex.com網站上找到。該技術框架經過7年多的發展,當前已發展到5.1版本,新增了包括移動客戶端模板、WebAPI模板、OAuth認證等功能在內的新特性,便於當前的以互聯網為主題背景的項目開發。

    在實際的項目中,主要面臨的兩個問題分別是:實際用戶使用的終端設備的廠商、型號等可能千變萬化,如何在不同的Web終端上呈現出適合的樣式;ASP.NET MVC默認提供WebForm和Razor兩種視圖引擎,但他們並不能支持HTML5頁面的呈現,如何擴展視圖引擎用於支持HTML5頁面的渲染。實際選擇的技術解決方案是,使用Media Queries等技術手段來實現響應式的CSS3設計,用自定義靜態HTML5視圖引擎擴展ASP.NET MVC框架。接下來,將分別詳細介紹兩個解決方案在項目中的實施應用。

    首先,介紹響應式的網頁布局,這個概念首先由Ethan Marcotte於2010年5月提出,目的是使得一個網站可以兼容多個終端—而不是為每一個終端開發一個特定的版本,可以說它就是為解決移動互聯網相關痛點應運而生的。實際上,當前正在運營的很多大型網站上,仍然是維護多套的網站程序,有的還使用不同的域名來服務不同的終端。同時往往對移動端網頁中的業務功能進行了一定的刪減,雖然也能提供不錯的用戶體驗,但這並不是最合理的解決方案,盡可能的統一用戶接口是很有必要的。響應式的頁面布局在具體的實現上,主要包含以下的幾個步驟。

第一步,在html頁面的head部分增加名為viewport的meta元素,viewport表示一個虛擬的窗口,通過它來設置適應移動設備屏幕的大小,代碼如下所示。

1  <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=0" />
2 <script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
View Code

    Content屬性中"width=device-width",表示寬度為當前設備寬度;"intial-scale=1"表示初始縮放倍數為1,;"user-scalable=0"表示不支持用戶手動縮放。同時增加css3-mediaqueries.js用於兼容IE6等老式瀏覽器。    

第二步,使用Media Queries模塊來根據不同的設備的可視屏幕大小來導入不同的CSS文件。該模塊的應用需要修改兩部分的內容,一部分是在HTML文件中增加3個不同條件下的CSS文件,另一部分是在CSS文件使用指定的形式將原有的內容包裝起來。代碼如下所示。

1 //Html文件中:
2 <link rel="stylesheet" type="text/css" media="only screen and (min-width:900px)" href="/content/theme/base/normalScreen.css" />
3 <link rel="stylesheet" type="text/css" media="only screen and (min-width:480px), only screen and (max-device-width:900)" href="/content/theme/base/smallScreen.css" />
4 <link rel="stylesheet" type="text/css" media="only screen and (max-width:480px)" href="/content/theme/base/tinyScreen.css" />
5 //CSS文件中:
6 @media screen and (min-width:900px) {
7 /*正常CSS內容,省略*/
8 }
View Code

    在HTML文件中,Media屬性中"screen and (min-width:900px)"表示媒體類型為屏幕,同時屏幕的最小寬度為900像素,only關鍵字使得不支持Media Queries的設備忽略該樣式文件,之后href屬性中為當前條件下所引用的CSS文件路徑。通常來說屏幕可見寬度小於480像素的設備為手機,介於480像素到900像素之間的為平板電腦,大於900像素的為台式機電腦。在CSS文件中,通過添加@media段與頁面中media屬性進行映射,其塊中所包含的內容與一般傳統網站的該文件相似,針對不同的設備,通過繼承的方式對樣式的布局進行一些細節的調整。

    最后一步,主要是處理前端開發中一些細節,包括使用相對的寬度,相對的字體大小、流動的布局、自適應的圖片等內容,和傳統的頁面開發相似,在此就不一一展開。最終的效果圖如下,可以看到同樣的內容在不同的設備上得到不一樣的渲染,以下是應用響應式頁面布局技術的效果圖。

 

    接下來介紹如何在ASP.NET MVC框架中擴展自定義的視圖引擎,使得框架能與HTML5技術無縫的銜接。之所以選擇ASP.NET MVC框架作為Web前端主要構件基礎,除了之前所提到的一些支持移動互聯網方面的新特性外,它內生所具備的高性能,高擴展性也起到了很大的作用。相對與重量級的WebForm框架,該框架顯得非常的輕量級,使得頁面渲染所消耗的資源得到了大幅的減少,並保留了認證、安全和本地緩存等模塊的支持。此外,該框架提供了極強的擴展性,無論是自行修改框架,還是在已有項目中增減業務模塊,都非常的方便。這一點,和JAVA陣營的J2EE技術很相似,但同時又具有很高的穩定性和較高的開發效率。例如可以自定義URL路由美化URL並提升搜索引擎排名,自定義數據綁定支持不同數據格式的序列化和反序列化,自定義視圖引擎應對不同的業務場景等。接下來,具體介紹如何實現自定義的HTML5視圖引擎,包含以下的步驟。

    第一步,創建自定義的HTML5視圖。它是讀取HTML5文件並呈現的基礎,需要實現System.Web.Mvc.IView接口,並實現接口中的Render方法,該方法主要通過流的方式讀取指定的HTML5文件並渲染到頁面,該部分內容比較簡單,簡化的代碼如下所示。

 1 public class HTML5View : IView
 2 {
 3 public string FileName { get; private set; }//文件名
 4 public HTML5View(string fileName)
 5 {
 6 this.FileName = fileName;
 7 }
 8  
 9 public void Render(ViewContext viewContext, TextWriter writer)
10 {
11 byte[] buffer = null;
12 using (var fs = new FileStream(this.FileName, FileMode.Open))
13 {
14 buffer = new byte[fs.Length];
15 fs.Read(buffer, 0, buffer.Length);
16 }
17 writer.Write(Encoding.UTF8.GetString(buffer));//讀取文件並渲染
18 }
19 }
View Code

  第二步,創建自定義緩存。由於HTML5FileView中都是靜態的內容,很自然的需要構建相應的緩存用於提高性能。創建頁面的緩存Key對象HTML5ViewCacheKey,實現GetHashCode方法,通過對Controller和View的名稱進行簡單的Hash組合運算等到緩存內容的Key,並實現Equals方法用於比較,簡化的代碼如下所示。

 1  public class HTML5ViewCacheKey
 2 {
 3 public string ControllerName { get; private set; }
 4 public string ViewName { get; private set; }
 5 public HTML5ViewCacheKey(string controllerName, string viewName)
 6 {
 7 this.ControllerName = controllerName ?? string.Empty;
 8 this.ViewName = viewName ?? string.Empty;
 9 }
10 
11 public override int GetHashCode()
12 {
13 return this.ControllerName.ToLower().GetHashCode() ^ this.ViewName.ToLower().GetHashCode();
14 } 
15 
16 public override bool Equals(object obj)
17 {
18 HTML5ViewCacheKey key = obj as HTML5ViewCacheKey;
19 if (null == key)
20 return false;
21 return key.GetHashCode() == this.GetHashCode();
22 }
23 }
View Code

  第三步,創建視圖引擎HTML5ViewEngine。該類實現了IViewEngine接口,字典類viewEngineResults結合第二步中構建的緩存類用於緩存渲染后的視圖。方法FindView首先解析路由信息獲得控制器的名稱,之后判斷請求是否支持緩存,若不支持緩存,則直接通過InternalFindView方法獲得視圖。反之,判斷請求視圖是否在本地緩存中,若存在直接返回,若不存在則調用方法獲取並緩存,寫緩存時注意加鎖。InternalFindView方法中,借助面向約定編程的思路到指定的路徑中尋找到對應的文件HTML5,最終完成URL信息與文件的映射。

 1 public class HTML5ViewEngine : IViewEngine
 2 {
 3 private Dictionary<HTML5ViewCacheKey, ViewEngineResult> viewEngineResults =
 4 new Dictionary<HTML5ViewCacheKey, ViewEngineResult>();
 5 private static object syncHelper = new object();
 6  
 7 public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
 8 {
 9 return this.FindView(controllerContext, partialViewName, null, useCache);
10 }
11 
12 public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
13 {
14 string controllerName = controllerContext.RouteData.GetRequiredString("controller");
15 var key = new HTML5ViewCacheKey(controllerName, viewName);
16 ViewEngineResult result = null;
17 if (!useCache)//是否支持緩存
18 {
19 result = InternalFindView(controllerContext, viewName, controllerName);
20 viewEngineResults[key] = result;
21 return result;
22 }
23 if (viewEngineResults.TryGetValue(key, out result)) //視圖是否已經在緩存中
24 {
25 return result;
26 }
27 
28 lock (syncHelper)//鎖定視圖數據寫入緩存過程
29 {
30 if (viewEngineResults.TryGetValue(key, out result))
31 {
32 return result;
33 }
34 result = InternalFindView(controllerContext, viewName, controllerName);
35 viewEngineResults[key] = result;
36 return result;
37 }
38 }
39 
40 private ViewEngineResult InternalFindView(ControllerContext controllerContext, string viewName, string controllerName)
41 {
42 string[] searchLocations = new string[]{
43 string.Format("~/staticViews/{0}/{1}.html", controllerName.ToLower(), viewName.ToLower()),
44 string.Format("~/staticViews/Shared/{0}.html", viewName.ToLower())
45 };
46 
47 string filename = controllerContext.HttpContext.Request.MapPath(searchLocations[0]);
48 if (File.Exists(filename))
49 {
50 return new ViewEngineResult(new HTML5View(filename), this);
51 }
52 filename = string.Format(@"\staticViews\shared\{0}.html", viewName.ToLower());
53 if (File.Exists(filename))
54 {
55 return new ViewEngineResult(new HTML5View(filename), this);
56 }
57 return new ViewEngineResult(searchLocations);
58 }
59 
60 public void ReleaseView(ControllerContext controllerContext, IView view)
61 {
62 }
63 }
View Code

   最后一步,將視圖自定義的視圖引擎添加到Global.asax文件的Application_Start方法中,完成該引擎的注冊。同時注意需要將該引擎的優先級設為最高,使得系統優先使用該引擎對視圖相關請求進行響應。

1  public class MvcApplication : System.Web.HttpApplication
2 {
3 protected void Application_Start()
4 {
5 //省略
6 ViewEngines.Engines.Insert(0, new HTML5ViewEngine());
7 }
View Code

通過以上步驟,基本上將ASP.NET MVC框架,HTML5技術,移動互聯網開發技術有機的整合到了一起。

系列目錄如下,謝謝您的閱讀。

快速入門系列--MVC--01概述

快速入門系列--MVC--02路由

快速入門系列--MVC--03控制器和IOC應用

快速入門系列--MVC--04模型

快速入門系列--MVC--05行為

快速入門系列--MVC--06視圖

快速入門系列--MVC--07與HTML5移動開發的結合

 

    Tip: 本文由於是學習需要,主要參考了以下書目。

[1]蔣金楠. ASP.NET MVC4框架揭秘[M]. 上海:電子工業出版社, 2012. 419-421

[2]唐俊開. HTML5移動Web開發指南[M]. 上海:電子工業出版社, 2012. 52-54


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM