找到最顶层的Layout是:Layout = "~/Views/Shared/_Root.Head.cshtml";
开始代码:
@using Nop.Core.Domain.Common; @using Nop.Core.Infrastructure; @{ var displayMiniProfiler = EngineContext.Current.Resolve<Nop.Core.Domain.StoreInformationSettings>().DisplayMiniProfilerInPublicStore; //resources Html.AppendCssFileParts("~/Content/jquery-ui-themes/smoothness/jquery-ui-1.10.3.custom.min.css"); Html.AppendScriptParts("~/Scripts/public.ajaxcart.js"); Html.AppendScriptParts("~/Scripts/public.common.js"); Html.AppendScriptParts("~/Scripts/jquery-migrate-1.2.1.min.js"); Html.AppendScriptParts("~/Scripts/jquery-ui-1.10.3.custom.min.js"); Html.AppendScriptParts("~/Scripts/jquery.validate.unobtrusive.min.js"); Html.AppendScriptParts("~/Scripts/jquery.validate.min.js"); Html.AppendScriptParts("~/Scripts/jquery-1.10.2.min.js"); //X-UA-Compatible tag var commonSettings = EngineContext.Current.Resolve<CommonSettings>(); if (commonSettings.RenderXuaCompatible) { Html.AppendHeadCustomParts(string.Format("<meta http-equiv=\"X-UA-Compatible\" content=\"{0}\"/>", commonSettings.XuaCompatibleValue)); } }
第一句从Setting表获得DisplayMiniProfilerInPublicStore的值查询是false.
第二句是HTMLHelper的扩展方法。整个类的代码:
namespace Nop.Web.Framework.UI { public static class LayoutExtensions { /// <summary> /// Add title element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Title part</param> public static void AddTitleParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddTitleParts(part); } /// <summary> /// Append title element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Title part</param> public static void AppendTitleParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendTitleParts(part); } /// <summary> /// Generate all title parts /// </summary> /// <param name="html">HTML helper</param> /// <param name="addDefaultTitle">A value indicating whether to insert a default title</param> /// <param name="part">Title part</param> /// <returns>Generated string</returns> public static MvcHtmlString NopTitle(this HtmlHelper html, bool addDefaultTitle, string part = "") { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); html.AppendTitleParts(part); return MvcHtmlString.Create(html.Encode(pageHeadBuilder.GenerateTitle(addDefaultTitle))); } /// <summary> /// Add meta description element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Meta description part</param> public static void AddMetaDescriptionParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddMetaDescriptionParts(part); } /// <summary> /// Append meta description element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Meta description part</param> public static void AppendMetaDescriptionParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendMetaDescriptionParts(part); } /// <summary> /// Generate all description parts /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Meta description part</param> /// <returns>Generated string</returns> public static MvcHtmlString NopMetaDescription(this HtmlHelper html, string part = "") { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); html.AppendMetaDescriptionParts(part); return MvcHtmlString.Create(html.Encode(pageHeadBuilder.GenerateMetaDescription())); } /// <summary> /// Add meta keyword element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Meta keyword part</param> public static void AddMetaKeywordParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddMetaKeywordParts(part); } /// <summary> /// Append meta keyword element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Meta keyword part</param> public static void AppendMetaKeywordParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendMetaKeywordParts(part); } /// <summary> /// Generate all keyword parts /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Meta keyword part</param> /// <returns>Generated string</returns> public static MvcHtmlString NopMetaKeywords(this HtmlHelper html, string part = "") { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); html.AppendMetaKeywordParts(part); return MvcHtmlString.Create(html.Encode(pageHeadBuilder.GenerateMetaKeywords())); } /// <summary> /// Add script element /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Script part</param> /// <param name="excludeFromBundle">A value indicating whether to exclude this script from bundling</param> public static void AddScriptParts(this HtmlHelper html, string part, bool excludeFromBundle = false) { AddScriptParts(html, ResourceLocation.Head, part, excludeFromBundle); } /// <summary> /// Add script element /// </summary> /// <param name="html">HTML helper</param> /// <param name="location">A location of the script element</param> /// <param name="part">Script part</param> /// <param name="excludeFromBundle">A value indicating whether to exclude this script from bundling</param> public static void AddScriptParts(this HtmlHelper html, ResourceLocation location, string part, bool excludeFromBundle = false) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddScriptParts(location, part, excludeFromBundle); } /// <summary> /// Append script element /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Script part</param> /// <param name="excludeFromBundle">A value indicating whether to exclude this script from bundling</param> public static void AppendScriptParts(this HtmlHelper html, string part, bool excludeFromBundle = false) { AppendScriptParts(html, ResourceLocation.Head, part, excludeFromBundle); } /// <summary> /// Append script element /// </summary> /// <param name="html">HTML helper</param> /// <param name="location">A location of the script element</param> /// <param name="part">Script part</param> /// <param name="excludeFromBundle">A value indicating whether to exclude this script from bundling</param> public static void AppendScriptParts(this HtmlHelper html, ResourceLocation location, string part, bool excludeFromBundle = false) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendScriptParts(location, part, excludeFromBundle); } /// <summary> /// Generate all script parts /// </summary> /// <param name="html">HTML helper</param> /// <param name="urlHelper">URL Helper</param> /// <param name="location">A location of the script element</param> /// <param name="bundleFiles">A value indicating whether to bundle script elements</param> /// <returns>Generated string</returns> public static MvcHtmlString NopScripts(this HtmlHelper html, UrlHelper urlHelper, ResourceLocation location, bool? bundleFiles = null) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); return MvcHtmlString.Create(pageHeadBuilder.GenerateScripts(urlHelper, location, bundleFiles)); } /// <summary> /// Add CSS element /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">CSS part</param> public static void AddCssFileParts(this HtmlHelper html, string part) { AddCssFileParts(html, ResourceLocation.Head, part); } /// <summary> /// Add CSS element /// </summary> /// <param name="html">HTML helper</param> /// <param name="location">A location of the script element</param> /// <param name="part">CSS part</param> public static void AddCssFileParts(this HtmlHelper html, ResourceLocation location, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddCssFileParts(location, part); } /// <summary> /// Append CSS element /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">CSS part</param> public static void AppendCssFileParts(this HtmlHelper html, string part) { AppendCssFileParts(html, ResourceLocation.Head, part); } /// <summary> /// Append CSS element /// </summary> /// <param name="html">HTML helper</param> /// <param name="location">A location of the script element</param> /// <param name="part">CSS part</param> public static void AppendCssFileParts(this HtmlHelper html, ResourceLocation location, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendCssFileParts(location, part); } /// <summary> /// Generate all CSS parts /// </summary> /// <param name="html">HTML helper</param> /// <param name="urlHelper">URL Helper</param> /// <param name="location">A location of the script element</param> /// <param name="bundleFiles">A value indicating whether to bundle script elements</param> /// <returns>Generated string</returns> public static MvcHtmlString NopCssFiles(this HtmlHelper html, UrlHelper urlHelper, ResourceLocation location, bool? bundleFiles = null) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); return MvcHtmlString.Create(pageHeadBuilder.GenerateCssFiles(urlHelper, location, bundleFiles)); } /// <summary> /// Add canonical URL element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Canonical URL part</param> public static void AddCanonicalUrlParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddCanonicalUrlParts(part); } /// <summary> /// Append canonical URL element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Canonical URL part</param> public static void AppendCanonicalUrlParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendCanonicalUrlParts(part); } /// <summary> /// Generate all canonical URL parts /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">Canonical URL part</param> /// <returns>Generated string</returns> public static MvcHtmlString NopCanonicalUrls(this HtmlHelper html, string part = "") { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); html.AppendCanonicalUrlParts(part); return MvcHtmlString.Create(pageHeadBuilder.GenerateCanonicalUrls()); } /// <summary> /// Add any custom element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">The entire element. For example, <![CDATA[<meta name="msvalidate.01" content="123121231231313123123" />]]></param> public static void AddHeadCustomParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AddHeadCustomParts(part); } /// <summary> /// Append any custom element to the <![CDATA[<head>]]> /// </summary> /// <param name="html">HTML helper</param> /// <param name="part">The entire element. For example, <![CDATA[<meta name="msvalidate.01" content="123121231231313123123" />]]></param> public static void AppendHeadCustomParts(this HtmlHelper html, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendHeadCustomParts(part); } /// <summary> /// Generate all custom elements /// </summary> /// <param name="html">HTML helper</param> /// <returns>Generated string</returns> public static MvcHtmlString NopHeadCustom(this HtmlHelper html) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); return MvcHtmlString.Create(pageHeadBuilder.GenerateHeadCustom()); } } }
跟踪下这个方法:
public static void AppendCssFileParts(this HtmlHelper html, string part) { AppendCssFileParts(html, ResourceLocation.Head, part); }
---》
/// <summary> /// Append CSS element /// </summary> /// <param name="html">HTML helper</param> /// <param name="location">A location of the script element</param> /// <param name="part">CSS part</param> public static void AppendCssFileParts(this HtmlHelper html, ResourceLocation location, string part) { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); pageHeadBuilder.AppendCssFileParts(location, part); }
他是调用IPageHeadBuilder的实现类PageHeadBuilder实现的AppendCssFileParts方法:
public virtual void AppendCssFileParts(ResourceLocation location, string part) { if (!_cssParts.ContainsKey(location)) _cssParts.Add(location, new List<string>()); if (string.IsNullOrEmpty(part)) return; _cssParts[location].Insert(0, part); }
cssParts是一个字典键值对,如果不包含这个location(是个枚举,传入的值是 ResourceLocation.head),则添加,值是一个string的List集合。
最后调用_cssParts[location].Add(part);这句,将part添加到LIST里。
下一句:
Html.AppendScriptParts("~/Scripts/public.ajaxcart.js");
public virtual void AppendScriptParts(ResourceLocation location, string part, bool excludeFromBundle) { if (!_scriptParts.ContainsKey(location)) _scriptParts.Add(location, new List<ScriptReferenceMeta>()); if (string.IsNullOrEmpty(part)) return; _scriptParts[location].Insert(0, new ScriptReferenceMeta { ExcludeFromBundle = excludeFromBundle, Part = part }); }
其实和加CSS一样,只是值换成了ScriptReferenceMeta(只有2个值得对象)对象。
后面代码:
var commonSettings = EngineContext.Current.Resolve<CommonSettings>(); if (commonSettings.RenderXuaCompatible) { Html.AppendHeadCustomParts(string.Format("<meta http-equiv=\"X-UA-Compatible\" content=\"{0}\"/>", commonSettings.XuaCompatibleValue)); }
数据库是false. X-UA-Compatible是一种浏览器兼容模式,可百度:http://www.cnblogs.com/nidilzhang/archive/2010/01/09/1642887.html
继续往下:<html @Html.Partial("LanguageAttributes")>
这句就是LanguageAttributes的部件。找到LanguageAttributes.cshtm文件,代码:
@if (this.ShouldUseRtlTheme()) { <text>dir="rtl"</text> //<text>dir="rtl" xml:lang="he" lang="he"</text> }
查看这个方法:
/// <summary> /// Return a value indicating whether the working language and theme support RTL (right-to-left) /// </summary> /// <returns></returns> public bool ShouldUseRtlTheme() { var supportRtl = _workContext.WorkingLanguage.Rtl; if (supportRtl) { //ensure that the active theme also supports it var themeProvider = EngineContext.Current.Resolve<IThemeProvider>(); var themeContext = EngineContext.Current.Resolve<IThemeContext>(); supportRtl = themeProvider.GetThemeConfiguration(themeContext.WorkingThemeName).SupportRtl; } return supportRtl; }
其实就是是否已支持 从右到左。类似中国 的字都是反写的。应该返回的是false,就不多研究了。
下面 <title>@Html.NopTitle(true)</title>,查看源码:
public static MvcHtmlString NopTitle(this HtmlHelper html, bool addDefaultTitle, string part = "") { var pageHeadBuilder = EngineContext.Current.Resolve<IPageHeadBuilder>(); html.AppendTitleParts(part); return MvcHtmlString.Create(html.Encode(pageHeadBuilder.GenerateTitle(addDefaultTitle))); }
实现类代码:
public virtual void AppendTitleParts(string part) { if (string.IsNullOrEmpty(part)) return; _titleParts.Insert(0, part); }
这里我们的part是“”,所以什么都没做。
最后一句return MvcHtmlString.Create(html.Encode(pageHeadBuilder.GenerateTitle(addDefaultTitle))); 的代码:
public virtual string GenerateTitle(bool addDefaultTitle) { string result = ""; var specificTitle = string.Join(_seoSettings.PageTitleSeparator, _titleParts.AsEnumerable().Reverse().ToArray()); if (!String.IsNullOrEmpty(specificTitle)) { if (addDefaultTitle) { //store name + page title switch (_seoSettings.PageTitleSeoAdjustment) { case PageTitleSeoAdjustment.PagenameAfterStorename: { result = string.Join(_seoSettings.PageTitleSeparator, _seoSettings.DefaultTitle, specificTitle); } break; case PageTitleSeoAdjustment.StorenameAfterPagename: default: { result = string.Join(_seoSettings.PageTitleSeparator, specificTitle, _seoSettings.DefaultTitle); } break; } } else { //page title only result = specificTitle; } } else { //store name only result = _seoSettings.DefaultTitle; } return result; }
大体意思就是返回一个title title分隔符来自于数据库setting的seoSettings.PageTitleSeparator进行分割。
如果为空就返回默认title(不研究了 ,应该简单)。
下一句:
<meta name="description" content="@(Html.NopMetaDescription())" />
哦 太慢了,以后不用这么详细,能省略就省略了。。。最终是这样:
public virtual string GenerateMetaDescription()
{
var metaDescription = string.Join(", ", _metaDescriptionParts.AsEnumerable().Reverse().ToArray());
var result = !String.IsNullOrEmpty(metaDescription) ? metaDescription : _seoSettings.DefaultMetaDescription;
return result;
}
就是返回逗号分割的string,或者数据库默认值。
<meta name="keywords" content="@(Html.NopMetaKeywords())" /> 不分析了 应该都一样。
后面一句:
public virtual string GenerateHeadCustom()
{
//use only distinct rows
var distinctParts = _headCustomParts.Distinct().ToList();
if (distinctParts.Count == 0)
return "";
var result = new StringBuilder();
foreach (var path in distinctParts)
{
result.Append(path);
result.Append(Environment.NewLine);
}
return result.ToString();
}
输出自定义部件。
@*This is used so that themes can inject content into the header*@
@Html.Partial("Head")
从注释可知,这里theme可以注入他们的内容。
事实也是如此,在theme里的head是有内容的,而主路径下的只有注释。:
@using Nop.Core; @using Nop.Core.Domain @using Nop.Core.Infrastructure @using Nop.Web.Framework.Themes @using Nop.Web.Framework.UI @{ var supportRtl = EngineContext.Current.Resolve<IWorkContext>().WorkingLanguage.Rtl; var supportResponsive = EngineContext.Current.Resolve<StoreInformationSettings>().ResponsiveDesignSupported; var themeName = EngineContext.Current.Resolve<IThemeContext>().WorkingThemeName; //we do not support responsive for RTL yet if (supportRtl) { supportResponsive = false; } //add browser specific CSS files var browser = Request.Browser; if (browser.Browser == "IE" && browser.MajorVersion == 6) { Html.AppendCssFileParts(string.Format("~/Themes/{0}/Content/ie6.css", themeName)); } else if (browser.Browser == "IE" && browser.MajorVersion == 7) { Html.AppendCssFileParts(string.Format("~/Themes/{0}/Content/ie7.css", themeName)); } //responsive design if (supportResponsive) { Html.AppendCssFileParts(string.Format("~/Themes/{0}/Content/responsive.css", themeName)); } //add main CSS file if (supportRtl) { Html.AppendCssFileParts(string.Format("~/Themes/{0}/Content/styles.rtl.css", themeName)); } else { Html.AppendCssFileParts(string.Format("~/Themes/{0}/Content/styles.css", themeName)); } //responsive design if (supportResponsive) { <meta name="viewport" content="width=device-width, initial-scale=1"> } }
第一二句,是获得RTL与响应式,注释说我们不支持响应式的RTL,也就是如果是RTL,就设置响应式为false.
第三局,字面理解 获得工作时的皮肤名称。找到实现类ThemeContext的方法WorkingThemeName。:
/// <summary> /// Get or set current theme system name /// </summary> public string WorkingThemeName { get { if (_themeIsCached) return _cachedThemeName; string theme = ""; if (_storeInformationSettings.AllowCustomerToSelectTheme) { if (_workContext.CurrentCustomer != null) theme = _workContext.CurrentCustomer.GetAttribute<string>(SystemCustomerAttributeNames.WorkingThemeName, _genericAttributeService, _storeContext.CurrentStore.Id); } //default store theme if (string.IsNullOrEmpty(theme)) theme = _storeInformationSettings.DefaultStoreTheme; //ensure that theme exists if (!_themeProvider.ThemeConfigurationExists(theme)) { var themeInstance = _themeProvider.GetThemeConfigurations() .FirstOrDefault(); if (themeInstance == null) throw new Exception("No theme could be loaded"); theme = themeInstance.ThemeName; } //cache theme this._cachedThemeName = theme; this._themeIsCached = true; return theme; } set { if (!_storeInformationSettings.AllowCustomerToSelectTheme) return; if (_workContext.CurrentCustomer == null) return; _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.WorkingThemeName, value, _storeContext.CurrentStore.Id); //clear cache this._themeIsCached = false; } }
原文:https://www.cnblogs.com/runit/p/4204041.html