我创建了一对能够解决您的问题的自定义标签助手。
第一个是<storecontent>
,它只是将包装在其中的 html 内容存储在 TempData 字典中。它不提供直接输出。内容可以是内联脚本或任何其他 html。许多此类标签助手可以放置在不同的位置,例如在局部视图中。
第二个标签助手是<renderstoredcontent>
,它将所有先前存储的内容呈现在所需位置,例如在正文元素的末尾。
代码StoreContentTagHelper.cs
:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
namespace YourProjectHere.TagHelpers
{
[TargetElement("storecontent", Attributes = KeyAttributeName)]
public class StoreContentTagHelper : TagHelper
{
private const string KeyAttributeName = "asp-key";
private const string _storageKey = "storecontent";
private const string _defaultListKey = "DefaultKey";
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
[HtmlAttributeName(KeyAttributeName)]
public string Key { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.SuppressOutput();
TagHelperContent childContent = await context.GetChildContentAsync();
var storageProvider = ViewContext.TempData;
Dictionary<string, List<HtmlString>> storage;
List<HtmlString> defaultList;
if (!storageProvider.ContainsKey(_storageKey) || !(storageProvider[_storageKey] is Dictionary<string,List<HtmlString>>))
{
storage = new Dictionary<string, List<HtmlString>>();
storageProvider[_storageKey] = storage;
defaultList = new List<HtmlString>();
storage.Add(_defaultListKey, defaultList);
}
else
{
storage = ViewContext.TempData[_storageKey] as Dictionary<string, List<HtmlString>>;
if (storage.ContainsKey(_defaultListKey))
{
defaultList = storage[_defaultListKey];
}
else
{
defaultList = new List<HtmlString>();
storage.Add(_defaultListKey, defaultList);
}
}
if (String.IsNullOrEmpty(Key))
{
defaultList.Add(new HtmlString(childContent.GetContent()));
}
else
{
if(storage.ContainsKey(Key))
{
storage[Key].Add(new HtmlString(childContent.GetContent()));
}
else
{
storage.Add(Key, new List<HtmlString>() { new HtmlString(childContent.GetContent()) });
}
}
}
}
}
代码RenderStoredContentTagHelper.cs
:
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
namespace YourProjectHere.TagHelpers
{
[TargetElement("renderstoredcontent", Attributes = KeyAttributeName)]
public class RenderStoredContentTagHelper : TagHelper
{
private const string KeyAttributeName = "asp-key";
private const string _storageKey = "storecontent";
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
[HtmlAttributeName(KeyAttributeName)]
public string Key { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = String.Empty;
var storageProvider = ViewContext.TempData;
Dictionary<string, List<HtmlString>> storage;
if (!storageProvider.ContainsKey(_storageKey) || !(storageProvider[_storageKey] is Dictionary<string, List<HtmlString>>))
{
return;
}
storage = storageProvider[_storageKey] as Dictionary<string, List<HtmlString>>;
string html = "";
if (String.IsNullOrEmpty(Key))
{
html = String.Join("", storage.Values.SelectMany(x => x).ToList());
}
else
{
if (!storage.ContainsKey(Key)) return;
html = String.Join("", storage[Key]);
}
TagBuilder tagBuilder = new TagBuilder("dummy");
tagBuilder.InnerHtml = html;
output.Content.SetContent(tagBuilder.InnerHtml);
}
}
}
基本用法:
在某些观点或部分观点中:
<storecontent asp-key="">
<script>
your inline script...
</script>
</storecontent>
在另一个位置:
<storecontent asp-key="">
<script src="..."></script>
</storecontent>
最后在需要渲染两个脚本的位置:
<renderstoredcontent asp-key=""></renderstoredcontent>
而已。
几点注意事项:
- 可以有任意数量的
<storecontent>
标签。该asp-key
属性是必需的,至少为空“”。如果您为此属性指定特定值,则可以对存储的内容进行分组并在不同位置呈现特定组。例如,如果您指定一些内容asp-key="scripts"
和一些其他内容,asp-key="footnotes"
那么您可以使用以下命令仅将第一组渲染为某个位置:
<renderstoredcontent asp-key="scripts"></renderstoredcontent>
另一组“脚注”可以在另一个位置呈现。
<storecontent>
必须在应用之前定义<renderstoredcontent>
。在 ASP.NET 中,响应以相反的层次顺序生成,首先生成最里面的部分视图,然后是父部分视图,然后是主视图,最后是布局页面。因此,您可以轻松地使用这些标签助手在局部视图中定义脚本,然后在布局页面的正文部分的末尾呈现脚本。
不要忘记使用命令在 _ViewImports.cshtml 文件中引用您的自定义标签助手@addTagHelper "*, YourProjectHere"
抱歉发了这么长的帖子,希望对您有所帮助!