Umbraco+VS2017开发:单文档实现内容动态变体的方法问询
当然可以!完全不用为每个变体创建独立文档,Umbraco提供了几种灵活的方式来实现单文档内的动态内容切换,我给你梳理几个最实用的方案,以及如何通过参数获取对应变体内容:
一、最推荐:用嵌套内容(Nested Content)管理变体
这是Umbraco官方推荐的轻量方案,适合内容变体结构一致的场景:
创建变体子文档类型
新建一个小型的Document Type(比如命名为BodyVariant),只包含两个核心字段:variantId:文本字段,用来标识每个变体(比如mobile、desktop、region-us)variantBody:富文本/文本字段,存放该变体的具体内容
在主文档类型中添加嵌套内容字段
回到你的目标Document Type,添加一个Nested Content类型的字段(比如命名为bodyVariants),设置允许关联的Document Type为刚才创建的BodyVariant,并允许添加多个条目——这样你就能在单个主文档里维护所有内容变体了。前端根据参数获取对应变体
在视图里,你可以通过传入的参数(比如URL的QueryString、路由参数)筛选出对应的变体内容:@{ // 从URL参数获取变体标识,比如 ?variant=mobile var targetVariantId = Request.QueryString["variant"]; // 获取主文档中的嵌套内容列表 var allVariants = Model.Value<IEnumerable<IPublishedElement>>("bodyVariants"); // 匹配对应的变体 var selectedVariant = allVariants?.FirstOrDefault(v => v.Value<string>("variantId") == targetVariantId); } <!-- 输出内容:找到变体则显示对应内容,否则显示默认内容 --> @if (selectedVariant != null) { @Html.Raw(selectedVariant.Value<string>("variantBody")) } else { @Html.Raw(Model.Value<string>("defaultBody")) <!-- 建议主文档保留一个默认内容字段 --> }
二、轻量替代:字典项+模板占位符
如果变体内容比较零散,不需要统一结构,可以用字典项配合内容占位符:
在Umbraco后台创建字典项
新建一个字典组(比如BodyVariants),然后为每个变体创建子字典项,比如BodyVariants/mobile、BodyVariants/desktop,分别填入对应内容。主文档内容中使用占位符
在主文档的body字段里,用占位符标记需要替换的部分,比如:欢迎访问我们的网站!{{mobile}}这是移动端专属内容{{/mobile}},{{desktop}}这是桌面端专属内容{{/desktop}}
或者更简单的全局替换:直接写
{{variant-content}},后续根据参数替换成对应字典项的值。前端动态替换占位符
@{ var variantKey = Request.QueryString["variant"]; var originalBody = Model.Value<string>("body"); var finalBody = originalBody; if (!string.IsNullOrEmpty(variantKey)) { // 从字典中获取变体内容 var variantContent = Umbraco.GetDictionaryValue($"BodyVariants/{variantKey}"); // 替换占位符 finalBody = finalBody.Replace($"{{{{{variantKey}}}}}", variantContent); } } @Html.Raw(finalBody)
三、进阶方案:自定义属性编辑器(适合复杂场景)
如果你的变体逻辑非常特殊(比如需要动态加载外部数据、复杂格式),可以自定义一个属性编辑器,让单个字段存储多个变体的JSON数据,然后前端解析JSON并根据参数输出内容:
创建自定义属性编辑器
你可以用Umbraco的包开发工具,或者手动编写一个简单的编辑器,让用户在后台输入多个变体的键值对,最终存储为JSON格式(比如{"mobile":"移动端内容","desktop":"桌面端内容"})。前端解析JSON并取值
@{ var variantKey = Request.QueryString["variant"]; var variantsJson = Model.Value<string>("bodyVariantsJson"); var variants = JsonConvert.DeserializeObject<Dictionary<string, string>>(variantsJson); string displayContent; if (variants != null && variants.TryGetValue(variantKey, out displayContent)) { @Html.Raw(displayContent) } else { @Html.Raw(Model.Value<string>("defaultBody")) } }
关于@Umbraco.Field("body")的参数调用说明
@Umbraco.Field本身并不支持直接传入变体参数,但你可以先通过上述方案获取到对应变体的内容,再输出。如果你想封装成类似@Umbraco.Field的便捷方法,可以自己写一个自定义的HtmlHelper扩展:
public static class UmbracoExtensions { public static IHtmlString VariantField(this UmbracoHelper umbraco, string fieldName, string variantId) { var currentNode = umbraco.AssignedContentItem; var variants = currentNode.Value<IEnumerable<IPublishedElement>>($"{fieldName}Variants"); var selectedVariant = variants?.FirstOrDefault(v => v.Value<string>("variantId") == variantId); return selectedVariant != null ? new HtmlString(selectedVariant.Value<string>(fieldName)) : new HtmlString(currentNode.Value<string>($"{fieldName}Default")); } }
然后在视图里就可以这样用:
@Umbraco.VariantField("body", Request.QueryString["variant"])
内容的提问来源于stack exchange,提问作者Unknown developer

