asp.net-core - 如何将 TagHelper 处理方法中生成的脚本渲染到页面底部而不是标签元素旁边?

标签 asp.net-core tag-helpers

我在 TagHelper 类的 process 方法中生成脚本,如下所示

[TargetElement("MyTag")]
    public Class MYClass: TagHelper{
      public override void Process(TagHelperContext context, TagHelperOutput output)
        {
StringBuilder builder = new StringBuilder();

                builder.Append("<script>");
                builder.Append("//some javascript codes here);
                builder.Append("</script>");
                output.Content.Append(builder.ToString());
}
}

现在,它将脚本放置在标签元素的旁边,作为其同级元素。

我需要将脚本放在正文部分的末尾。

最佳答案

我创建了一对自定义标签助手,可以解决您的问题。

第一个是<storecontent>它只是将包裹在其中的 html 内容存储在 TempData 字典中。它不提供直接输出。内容可以是内联脚本或任何其他 html。许多这种类型的标签助手可以放置在不同的位置,例如在局部 View 中。

第二个标签助手是 <renderstoredcontent>并将所有先前存储的内容呈现在所需的位置,例如在 body 元素的末尾。

代码 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);
        }
    } 
} 

基本用法:

在某些 View 或部分 View 中:

<storecontent asp-key="">
  <script>
    your inline script...
  </script>
</storecontent>

在另一个位置:

<storecontent asp-key="">
  <script src="..."></script>
</storecontent>

最后在应该呈现两个脚本的所需位置:

<renderstoredcontent asp-key=""></renderstoredcontent>

就是这样。

一些注意事项:

  1. 可以有任意数量的 <storecontent>标签。 asp-key属性是必需的,至少为空“”。如果您为此属性指定特定值,则可以对存储的内容进行分组并在不同位置呈现特定组。例如。如果您使用 asp-key="scripts" 指定一些内容以及其他一些内容 asp-key="footnotes"那么您可以使用以下方法仅将第一组渲染为某个位置:

<renderstoredcontent asp-key="scripts"></renderstoredcontent>

另一组“脚注”可以在其他位置呈现。

  • <storecontent>必须在 <renderstoredcontent> 之前定义被申请;被应用。在 ASP.NET 中,响应是以相反的层次顺序生成的,首先生成最里面的部分 View ,然后是父部分 View ,然后是主视图,最后是布局页面。因此,您可以轻松地使用这些标签助手在分部 View 中定义脚本,然后在布局页面中的正文部分的末尾呈现脚本。

  • 不要忘记使用命令 @addTagHelper "*, YourProjectHere" 在 _ViewImports.cshtml 文件中引用自定义标记助手。

  • 很抱歉这篇文章很长,希望对您有所帮助!

    关于asp.net-core - 如何将 TagHelper 处理方法中生成的脚本渲染到页面底部而不是标签元素旁边?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31313529/

    相关文章:

    css - 在 ASP.NET Core 2.2 应用程序中使用自定义 .otf 字体

    c# - 跳过特定 Controller API 上的 [Authorize] 属性以获得可选授权是否安全?

    c# - 从字符串渲染标签助手 html

    asp.net - 如何从 Tag Helper 访问 Request 对象

    c# - ASP.NET Core CORS WebAPI : no Access-Control-Allow-Origin header

    c# - ASP.NET Core - 提供静态文件

    html - 是否可以在 html 中将单选按钮标签助手值属性设置为 "checked"?

    asp.net-core-mvc - MVC6 TagHelpers 一次性

    c# - 如何对 ViewComponent.Invoke() 进行单元测试?

    asp.net-mvc - 在 Tag Helper 中获取属性名称