七、制作主题(五) Alternates
Alternates是shape选项的变种,在特殊情况下为了你能在主题中实现定制呈现shape,使用Alternates,你能基于内容的类型重写用于呈现内容的模板。例如:你能使用alternates为主页应用一个layout文件,为subpages应用另一个layout文件,或者你能当tags在page中时用alternates以一种方式呈现tags,在blog post中时用另外一种方式呈现。
Orchard framework使用一个命名约定决定是否用一个模板呈现内容。命名约定使你添加文件能自动地使用,不需要修改任何代码。
Naming Convention for Alternates
Alternate shapes使用基于shape的名称紧跟一个双下划线(__)和具体alternate shape的结束符,例如:Parts_Tags_ShowTags shape能有Parts_Tags_ShowTags__BlogPost
andParts_Tags_ShowTags__Page这样的Alternate shapes,当shape被使用时候选名称的一部分在双下划线之后,如当前的内容类型。
Mapping a Template File to an Alternate
要创建对应shape name到一个模板文件的映射,你必须根据下面约定命名模板:
- 转换shape名称中的下划线为模板名称中 点(.)或反斜线符号(\)。反斜线代表子文件夹中的模板。
- 转换shape名称中的双下划线(__)为字符连接符(-).
- 对于shape name中显示的类型值 替换 模板名称结尾的点(.)之后的类型名称。如Content-BlogPost.Summary。
所有alternates模板必须在Views文件夹中,Views文件夹能在主题 或模块中。下表展示为不同类型的模板使用哪个Views子文件夹
Shape type | Template Folder |
Content item | Views\Items |
Parts | Views\Parts |
Fields | Views\Fields |
EditorTemplate | Views\EditorTemplates\[template type folder] (For example, an EditorTemplate for a part is located at Views\EditorTemplates\Parts.) |
All other | Views |
例如:为Tags part创建候选模板,你能将模板放入MyTheme\Views\Parts文件夹中。不过,因为下划线会被转换为点或反斜线,你也能在Views中创建模板和添加part. 作为名称的开始。在Views\Parts\Tags.ShowTags-BlogPost.cshtml 或 Views\Parts.Tags.ShowTags-BlogPost.cshtml中的模板会被映射到shape 名为 Parts_Tags_ShowTags__BlogPost。
如果Orchard framework不能定位有预期名称的候选模板,会为那个shape使用默认的模板。
Orchard framework自动创建许多候选,你能在程序中使用。可是,你也能为这些候选shapes创建模板。创建候选的模式如下面所示:括号中为匹配模板的例子
For Contentshapes:
- Content__[DisplayType]. (Example template:
Content.Summary
) - Content__[ContentType]. (Example template:
Content-BlogPost
) - Content__[Id]. (Example template:
Content-42
) - Content[DisplayType]__[ContentType]_. (Example template:
Content-BlogPost.Summary
) - Content[DisplayType]__[Id]_. (Example template:
Content-42.Summary
)
For Zoneshapes:
- Zone__[ZoneName]. (Example template:
Zone-SideBar
)
For menu and menu item shapes:
- Menu__[MenuName]. (Example template:
Menu-main
) - MenuItem__[MenuName]. (Example template:
MenuItem-main
)
For local menu and local menu item shapes:
- LocalMenu__[MenuName]. (Example template:
LocalMenu-main
) - LocalMenuItem__[MenuName]. (Example template:
LocalMenuItem-main
)
For styles and resources:
- Style__[FileName]
- Resource__[FileName]
For widget shapes:
- Widget__[ZoneName]. (Example template:
Widget-SideBar
) - Widget__[ContentType]. (Example template:
Widget-BlogArchive
)
For fields:
- [ShapeType__FieldName]. (Example template:
Fields\Common.Text-Teaser
) - [ShapeType__PartName]. (Example template:
Fields\Common.Text-TeaserPart
) - [ShapeType]__[ContentType]__[PartName]. (Example template:
Fields\Common.Text-Blog-TeaserPart
) - [ShapeType]__[PartName]__[FieldName]. (Example template:
Fields\Common.Text-TeaserPart-Teaser
) - [ShapeType]__[ContentType]__[FieldName]. (Example template:
Fields\Common.Text-Blog-Teaser
) - [ShapeType]__[ContentType]__[PartName]__[FieldName]. (Example template:
Fields\Common.Text-Blog-TeaserPart-Teaser
)
For content parts:
- [ShapeType]__[Id]. (Example template:
Parts\Common.Metadata-42
) - [ShapeType]__[ContentType]. (Example template:
Parts\Common.Metadata-BlogPost
)
URL and Widget Alternates
URL Alternates模块使你能为特殊的URLs创建模板,Widget Alternates使你能在具体的zones中为某个类型的widgets创建额外的候选widget,你必须先启用URL Alternates and Widget Alternate模块的功能,当启用后候选shape会基于URL或zone被创建,这些URL候选是用上面定义的alternate模式组合。
例如:the URL /my-blog/post-1 有关于MenuItem对象的候选,使用下面这样的模板名称:
MenuItem-main
MenuItem-main-url-my-blog
MenuItem-main-url-my-blog-post-1
For the homepage, the following alternate is available:
MenuItem-main-url-homepage
使用这个模块,能添加URL-specific alternates到Layout shape,如下面的:
Layout-url-homepage
.为网站的about页添加一个具体的layout:在Themes/ThemeName/Views创建一个名为Layout-url-About.cshtml的新Layout,当访问/About时将会使用。
能从Gallery下载Orchard Designer Tools并启用。
Explicitly Designating an Alternate Template
除了使用自动生成的alternates,你能手动创建一个具体的alternate。在placement.info文件中,能为一个内容类型指定哪个alternates可用。例如:要为呈现blog posts的tags指定一个不同的模板( Parts_Tags_ShowTags_BlogPost作标识),你能修改Orchard.Tags模块的placement.info文件为包含匹配BlogPost类型的元素,下面是修改的示例:
<Placement> <Place Parts_Tags_Edit="Content:7"/> <Match ContentType="BlogPost"> <Place Parts_Tags_ShowTags="Header:after.7;Alternate=ShowTags_BlogPost"/> </Match> <Match DisplayType="Detail"> <Place Parts_Tags_ShowTags="Header:after.7"/> </Match> <Match DisplayType="Summary"> <Place Parts_Tags_ShowTags="Header:after.7"/> </Match> </Placement>
匹配元素的排序是重要的,仅第一个匹配的元素会被使用。在这个例子中,把BlogPost 元素放在Detail and Summary 下面, ShowTags_BlogPost将不会被使用,甚至关于BlogPost items,因为前面的元素匹配 这个item。
Adding Alternates Through Code
除了上面描述的添加alternates的方法外,你能通过代码添加alternates。要通过指明alternate需要创建一个
实现IShapeTableProvider接口的类,然后,为需要alternate的每种类型的shape的
OnDisplaying
添加处理程序,为ShapeTableBuilder类中的
Describe方法指定shape name的参数,处理程序内,添加当alternate使用时需要指定的所有逻辑。下面示例首先展示了为名为Content的shape如何指定一个alternate,但仅当用户在首页时, 它也展示了名为Parts_Tags_ShowTags的shape如何指定一个alternate,当DisplayType是Summary时,
using Orchard; using Orchard.ContentManagement; using Orchard.DisplayManagement.Descriptors; namespace MyTheme.ShapeProviders { public class ExampleShapeProvider : IShapeTableProvider { private readonly IWorkContextAccessor _workContextAccessor; public ExampleShapeProvider(IWorkContextAccessor workContextAccessor) { _workContextAccessor = workContextAccessor; } public void Discover(ShapeTableBuilder builder) { builder.Describe("Content") .OnDisplaying(displaying => { if (displaying.ShapeMetadata.DisplayType == "Detail") { ContentItem contentItem = displaying.Shape.ContentItem; if (_workContextAccessor.GetContext().CurrentSite.HomePage .EndsWith(';' + contentItem.Id.ToString())) { displaying.ShapeMetadata.Alternates .Add("Content__HomePage"); } } }); builder.Describe("Parts_Tags_ShowTags") .OnDisplaying(displaying => { if (displaying.ShapeMetadata.DisplayType == "Summary") { displaying.ShapeMetadata.Alternates .Add("Tags_ShowTags_Summary"); } }); } } }