编程 |  数据库 |  安全 |  系统 |  服务器 |  嵌入式 |  设计 |  基础 |  组网 |  QQ | 

NopCommerce Web层中的布局页

作者:我佛慈悲纠结  发布日期:2013-12-09 22:09:50
  • 收藏本文    我要投稿
  •   援引上一篇文章关于nopcommerce源代码结构的翻译:“Nop.Web也是一个MVC Web应用程序项目,一个公有区域的展示层。它就是你实际能够运行的应用程序。它是应用程序的启动项目”。对于nopcommerce这样电子商务系统来说,Nop.Web是我们用户所看到的界面,比如商品列表。

    一 概况                                                                                                                                            

      nopcommerce其布局页文件分布在Nop.Web/Views/shared当中,主要涉及到五个布局文件:_Root.Head.cshtml、_Root.cshtml、_ColumnsOne.cshtml、_ColumnsTwo.cshtml、_ColumnsThree.cshtml。_ColumnsOne(Two/Three).cshtml三个布局页继承自_Root.cshtml、_Root.cshtml继承自_Root.Head.cshtml。

      所有继承_Root.Head.cshtml的页面将会使用相同的<head>标签内容,<body>体由它的子布局页来进一步细化。

      _Root.cshtml此页面替换掉_Root.Head.cshtml中@RenderBody(),大致结构如下图:

      Designer

      

      Designer

      

      也就是说_Root.Head主要管<head>中内容设置,以及全局CSS、JS文件引入;_Root.cshtml将网页主体内容<body>设计完成;_ColumnsOne(Two/Three).cshtml对_Root.cshtml变形处理。

    二 、细读                                                              

      1._Root.Head.cshtml

      顶层_Root.Head.cshtml内容如下:

    _Root.Head.cshtml

      在程序中,已经写了一些注释供大家参考。

      1.1. Html.AppendCssFileParts() 与AppendScriptParts()

       两个方法都是nop为HtmlHelper类定义拓展方法。见名知意,AppendCssFileParts附加CSS文件,AppendScriptParts附加脚本文件:

     


     1  // private readonly Dictionary<ResourceLocation, List<string>> _cssParts;
     2 
     3  public virtual void AppendCssFileParts(ResourceLocation location, string part)
     4         {
     5             if (!_cssParts.ContainsKey(location))
     6                 _cssParts.Add(location, new List<string>());
     7 
     8             if (string.IsNullOrEmpty(part))
     9                 return;
    10             
    11             _cssParts[location].Insert(0, part);
    12         }
    AppendCssFileParts

      _cssParts为字典类型,根据传入的location确定键值,而字符串参数 part是CSS文件的路径。此方法最终就是将传入的CSS文件路径附加到_cssParts Dictionary当中。

    与此对应还有一个AddCssFileParts。


     1  public virtual void AddCssFileParts(ResourceLocation location, string part)
     2         {
     3             if (!_cssParts.ContainsKey(location))
     4                 _cssParts.Add(location, new List<string>());
     5 
     6             if (string.IsNullOrEmpty(part))
     7                 return;
     8              //注意这里
     9             _cssParts[location].Add(part);
    10         }
    AddCssFileParts

      注意到两者的差别仅仅是给Dictionary<ResourceLocation, List<string>>添加值顺序的不同,Append在Dictionary索引为0处添加,Add在队列末尾添加。因此产生的效果是:AppendCssFileParts()调用越靠后,在界面上显示反而越靠前。大家在_Root.Head.cshtml代码中可以看到 jquery-1.7.1.min.js的引用是在最后,但是通常我们是应该将其引用位置尽量考前。

      AppendScriptParts()与AppendCssFileParts()非常相似,这里就不再贴代码说明。

      1.2 @Html.Partial('LanguageAttributes')

      就是字符串:


    1 @if (this.ShouldUseRtlTheme())
    2 {
    3     <text>dir='rtl'</text>
    4     //<text>dir='rtl' xml:lang='he' lang='he'</text>
    5 }
    LanguageAttributes.cshtml

      ShouldUseRtlTheme()方法从当前用户的配置信息中读取其阅读方式是左到右,还是右到左,其实现依托<html>标签 的dir属性。

      1.3 @(Html.NopMetaDescription()

      NopMetaDescription方法中调用下面关键方法:


    1 // private readonly List<string> _metaDescriptionParts;
    2 public virtual string GenerateMetaDescription()
    3         {
    4             var metaDescription = string.Join(', ', _metaDescriptionParts.AsEnumerable().Reverse().ToArray());
    5             var result = !String.IsNullOrEmpty(metaDescription) ? metaDescription : _seoSettings.DefaultMetaDescription;
    6             return result;
    7         }
    GenerateMetaDescription

      DefaultMetaDescription是属性,从数据库中查取。

      1.4 @Html.Action('RssHeaderLink', 'News')、@Html.Action('RssHeaderLink', 'Blog')

      返回形如这样的字符串:<link href='xx' rel='alternate' ……>,用于RSS。

      1.5 @Html.Action('Favicon', 'Common')

       返回的字符串形式这样: <link rel='shortcut icon' href='XX' />,href属性默认寻找Nop.Web根目录下名字为favicon.ico文件。

      2._Root.cshtml 

      _Root.cshtml内容如下:


     1 @{
     2     Layout = '~/Views/Shared/_Root.Head.cshtml';
     3 }
     4 @Html.Widget('body_start_html_tag_after')
     5 @Html.Partial('_Notifications')
     6 @Html.Action('AdminHeaderLinks', 'Common')
     7 <div class='master-wrapper-page'>
     8     @Html.Action('JavaScriptDisabledWarning', 'Common')
     9     <div class='master-wrapper-content'>
    10         <script type='text/javascript'>
    11             AjaxCart.init(false, '.header-links .cart-qty', '.header-links .wishlist-qty', '#flyout-cart');
    12         </script>
    13         @Html.Partial('Header')
    14         <div class='header-menu'>
    15             @Html.Action('Menu', 'Common')
    16         </div>
    17         @Html.Widget('content_before')
    18         @*ajax loading window*@
    19         <div class='ajax-loading-block-window' style='display: none'>
    20             <div class='loading-image'>
    21             </div>
    22         </div>
    23         <div class='master-wrapper-main'>
    24             @RenderBody()
    25         </div>
    26         @Html.Widget('content_after')
    27        @* Eu Cookie Law 欧盟cookie新法:http://www.theeucookielaw.com/ 在用户机器上替换cookie前必须先通知客户*@
    28         @Html.Action('EuCookieLaw', 'Common')
    29     </div>
    30     @Html.Action('Footer', 'Common')
    31 </div>
    32 @Html.Widget('body_end_html_tag_before')
    _Root.cshtml

      2.1  @Html.Action('JavaScriptDisabledWarning', 'Common')

      返回一个PartialView:

      


     1 @model dynamic
     2 @*此标签详情:http://www.w3school.com.cn/tags/tag_noscript.asp*@
     3 <noscript>
     4     <div class='noscript'>
     5         <p>
     6             <strong>JavaScript seem to be disabled in your browser.</strong></p>
     7         <p>
     8             You must have JavaScript enabled in your browser to utilize the functionality of
     9             this website.</p>
    10     </div>
    11 </noscript>
    JavaScriptDisabledWarning

      其目的就是检测是否禁用JS,如果禁用就提示。

      2.2 @Html.Partial('_Notifications')

      弹出提示: 


     1 @{
     2     //success messages
     3     var successMessages = new List<string>();
     4     if (TempData[string.Format('nop.notifications.{0}', NotifyType.Success)] != null)
     5     {
     6         successMessages.AddRange(TempData[string.Format('nop.notifications.{0}', NotifyType.Success)] as IList<string>);
     7     }
     8     if (ViewData[string.Format('nop.notifications.{0}', NotifyType.Success)] != null)
     9     {
    10         successMessages.AddRange(ViewData[string.Format('nop.notifications.{0}', NotifyType.Success)] as IList<string>);
    11     }
    12 
    13 
    14     //error messages
    15     var errorMessages = new List<string>();
    16     if (TempData[string.Format('nop.notifications.{0}', NotifyType.Error)] != null)
    17     {
    18         errorMessages.AddRange(TempData[string.Format('nop.notifications.{0}', NotifyType.Error)] as IList<string>);
    19     }
    20     if (ViewData[string.Format('nop.notifications.{0}', NotifyType.Error)] != null)
    21     {
    22         errorMessages.AddRange(ViewData[string.Format('nop.notifications.{0}', NotifyType.Error)] as IList<string>);
    23     }
    24 }
    25 @*TODO use 'displayPopupNotification' java-script function*@
    26 @if (successMessages.Count > 0)
    27 {
    28     <script type='text/javascript'>
    29         $(document).ready(function () {
    30             $('#dialog-notifications-success').dialog({ modal: true });
    31         });
    32     </script>
    33 }
    34 @if (errorMessages.Count > 0)
    35 {
    36     <script type='text/javascript'>
    37         $(document).ready(function () {
    38             $('#dialog-notifications-error').dialog({ modal: true });
    39         });
    40     </script>
    41 }
    42 <div id='dialog-notifications-success' title='@T('Common.Notification')' style='display:none;'>
    43     @foreach (var message in successMessages)
    44     {
    45         <p>@message</p>
    46     }
    47 </div>
    48 <div id='dialog-notifications-error' title='@T('Common.Error')' style='display:none;'>
    49     @foreach (var message in errorMessages)
    50     {
    51         <p>@message</p>
    52     }
    53 </div>
    54 <div id='bar-notification' class='bar-notification'>
    55     <img src='@Url.Content('~/Content/Images/ico-close-notification-bar.png')' class='close' alt='Close' title='Close' />
    56 </div>
    57 @Html.Widget('notifications')
    _Notifications

      通知内容通过TempData[nop.notifications.sucess]获取,注意到使用的是TempData,所以nop的通知是跨action的。

      2.3  @Html.Partial('Header')

      对应第一部分图中header,包含了头部链接、搜索框等内容。

      2.4  @Html.Action('Menu', 'Common')

      菜单,对应第一部分图中的Menu,这个好理解。

     

Tag标签:NopCommerce    Web  
  • 专题推荐