it-swarm.com.de

Füllen Sie einen Rasiererabschnitt aus einem Teil

Meine Hauptmotivation dafür ist, Javascript zu bekommen, das nur von einem Teil am unteren Rand der Seite mit dem Rest des Javascript benötigt wird, und nicht in der Mitte der Seite, wo das Teil gerendert wird. 

Hier ist ein vereinfachtes Beispiel für das, was ich versuche:

Hier ist das Layout mit einem Skriptabschnitt direkt vor dem Körper.

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />    
</head>

<body>
    @RenderBody()
    <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
    @RenderSection("Scripts", false)
</body>
</html>

Hier ist eine Beispielansicht mit diesem Layout. 

<h2>This is the view</h2>

@{Html.RenderPartial("_Partial");}

@section Scripts {
<script type="text/javascript">
        alert("I'm a view.");
</script>
}

Und hier ist das teilweise aus der Ansicht gerendert.

<p>This is the partial.</p>

@* this never makes it into the rendered page *@
@section Scripts {
<script type="text/javascript">
    alert("I'm a partial."); 
</script>
}

In diesem Beispiel wird das in der Ansicht angegebene Markup in den Abschnitt eingefügt, nicht jedoch das aus dem Partial. Ist es möglich, einen Ausschnitt aus einer Teilansicht mit Razor zu füllen? Wenn nicht, was sind andere Methoden, um Javascript zu erhalten, das nur von Partials am unteren Rand der Seite benötigt wird, ohne es global einzubinden?

97
Craig M

In diesem Zusammenhang habe ich einige Erweiterungsmethoden für die Klasse HtmlHelper geschrieben. Auf diese Weise können Teilansichten sagen, dass sie ein Skript erfordern, und dann in der Layoutansicht, die das von mir aufgerufene Tag in meine Hilfsmethode schreibt, um die erforderlichen Skripts auszugeben

Hier sind die Hilfsmethoden:

public static string RequireScript(this HtmlHelper html, string path, int priority = 1)
{
    var requiredScripts = HttpContext.Current.Items["RequiredScripts"] as List<ResourceInclude>;
    if (requiredScripts == null) HttpContext.Current.Items["RequiredScripts"] = requiredScripts = new List<ResourceInclude>();
    if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority });
    return null;
}

public static HtmlString EmitRequiredScripts(this HtmlHelper html)
{
    var requiredScripts = HttpContext.Current.Items["RequiredScripts"] as List<ResourceInclude>;
    if (requiredScripts == null) return null;
    StringBuilder sb = new StringBuilder();
    foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
    {
        sb.AppendFormat("<script src=\"{0}\" type=\"text/javascript\"></script>\n", item.Path);
    }
    return new HtmlString(sb.ToString());
}
public class ResourceInclude
{
    public string Path { get; set; }
    public int Priority { get; set; }
}

Sobald Sie diese Funktion eingerichtet haben, muss Ihre Teilansicht nur @Html.RequireScript("/Path/To/Script") aufrufen.

Und im Kopfbereich der Layoutansicht rufen Sie @Html.EmitRequiredScripts() auf.

Ein zusätzlicher Vorteil davon ist, dass Sie doppelte Skriptanfragen entfernen können. Wenn Sie mehrere Ansichten/Teilansichten haben, die ein bestimmtes Skript benötigen, können Sie davon ausgehen, dass Sie es nur einmal ausgeben

77
Mr Bell

Teilansichten können nicht an den Abschnitten ihrer übergeordneten Ansichten teilnehmen.

27
SLaks

Möglicherweise haben Sie einen zweiten Teil, der nur für das erforderliche Javascript zuständig ist. Platzieren Sie mehrere Skripts um @if-Blöcke, wenn Sie möchten:

@model string
@if(Model == "bla") {
    <script type="text/javascript">...</script>
}

@else if(Model == "bli") {
    <script type="text/javascript">...</script>
}

Dies könnte natürlich etwas aufgeräumt werden, aber dann in der Scripts-Ansicht Ihrer Ansicht:

@section Scripts
{
    @Html.Partial("_Scripts", "ScriptName_For_Partial1")
}

Auch hier wird möglicherweise kein Schönheitspreis gewonnen, aber es funktioniert.

12
Sergi Papaseit

Der elegantere Weg, dies zu tun, ist das Verschieben von Teilansichtsskripts in eine separate Datei und das Rendern im Teilabschnitt "Scripts":

<h2>This is the view</h2>

@Html.RenderPartial("_Partial")

@section Scripts
{
    @Html.RenderPartial("_PartialScripts")

    <script type="text/javascript">
        alert("I'm a view script.");
    </script>
}

Die Teilansicht _ Partial.cshtml :

<p>This is the partial.</p>

Die Teilansicht _ PartialScripts.cshtml nur mit Skripts:

<script type="text/javascript">
    alert("I'm a partial script!");
</script>
8
Vlad Rudenko

Installieren Sie das - Forloop.HtmlHelpers - Nuget-Paket. Es enthält einige Hilfsmittel zum Verwalten von Skripts in Teilansichten und Editorvorlagen.

Irgendwo in Ihrem Layout müssen Sie anrufen 

@Html.RenderScripts()

An dieser Stelle werden alle Skriptdateien und Skriptblöcke auf der Seite ausgegeben. Daher würde ich empfehlen, sie nach Ihren Hauptskripten im Layout und nach einem Skriptabschnitt (falls vorhanden) zu setzen.

Wenn Sie das Web Optimization Framework mit Bundling verwenden, können Sie die Überladung verwenden

@Html.RenderScripts(Scripts.Render)

so dass diese Methode zum Schreiben von Skriptdateien verwendet wird.

Wenn Sie nun Skriptdateien oder Blöcke in einer Ansicht, Teilansicht oder Vorlage hinzufügen möchten, verwenden Sie sie einfach

@using (Html.BeginScriptContext())
{
  Html.AddScriptFile("~/Scripts/jquery.validate.js");
  Html.AddScriptBlock(
    @<script type="text/javascript">
       $(function() { $('#someField').datepicker(); });
     </script>
  );
}

Die Helfer stellen sicher, dass nur ein Skriptdateiverweis wiedergegeben wird, wenn sie mehrmals hinzugefügt werden. Außerdem wird sichergestellt, dass Skriptdateien in der erwarteten Reihenfolge ausgegeben werden, d. H.

  1. Layout
  2. Partials und Vorlagen (in der Reihenfolge, in der sie in der Ansicht von oben nach unten erscheinen)
7
Russ Cam

[Aktualisierte Version] Aktualisierte Version nach der @Necrocubus-Frage zum Einbinden von Inline-Skripts.

public static class ScriptsExtensions
{
    const string REQ_SCRIPT = "RequiredScript";
    const string REQ_INLINESCRIPT = "RequiredInlineScript";
    const string REQ_STYLE = "RequiredStyle";

    #region Scripts
    /// <summary>
    /// Adds a script 
    /// </summary>
    /// <param name="html"></param>
    /// <param name="path"></param>
    /// <param name="priority">Ordered by decreasing priority </param>
    /// <param name="bottom"></param>
    /// <param name="options"></param>
    /// <returns></returns>
    public static string RequireScript(this IHtmlHelper html, string path, int priority = 1, bool bottom=false, params string[] options)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_SCRIPT] as List<ResourceToInclude>;
        if (requiredScripts == null) ctxt.Items[REQ_SCRIPT] = requiredScripts = new List<ResourceToInclude>();
        if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceToInclude() { Path = path, Priority = priority, Options = options, Type=ResourceType.Script, Bottom=bottom});
        return null;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="html"></param>
    /// <param name="script"></param>
    /// <param name="priority">Ordered by decreasing priority </param>
    /// <param name="bottom"></param>
    /// <returns></returns>
    public static string RequireInlineScript(this IHtmlHelper html, string script, int priority = 1, bool bottom = false)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_INLINESCRIPT] as List<InlineResource>;
        if (requiredScripts == null) ctxt.Items[REQ_INLINESCRIPT] = requiredScripts = new List<InlineResource>();
        requiredScripts.Add(new InlineResource() { Content=script, Priority = priority, Bottom=bottom, Type=ResourceType.Script});
        return null;
    }

    /// <summary>
    /// Just call @Html.EmitRequiredScripts(false)
    /// at the end of your head tag and 
    /// @Html.EmitRequiredScripts(true) at the end of the body if some scripts are set to be at the bottom.
    /// </summary>
    public static HtmlString EmitRequiredScripts(this IHtmlHelper html, bool bottom)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_SCRIPT] as List<ResourceToInclude>;
        var requiredInlineScripts = ctxt.Items[REQ_INLINESCRIPT] as List<InlineResource>;
        var scripts = new List<Resource>();
        scripts.AddRange(requiredScripts ?? new List<ResourceToInclude>());
        scripts.AddRange(requiredInlineScripts ?? new List<InlineResource>());
        if (scripts.Count==0) return null;
        StringBuilder sb = new StringBuilder();
        foreach (var item in scripts.Where(s=>s.Bottom==bottom).OrderByDescending(i => i.Priority))
        {
            sb.Append(item.ToString());
        }
        return new HtmlString(sb.ToString());
    }
    #endregion Scripts

    #region Styles
    /// <summary>
    /// 
    /// </summary>
    /// <param name="html"></param>
    /// <param name="path"></param>
    /// <param name="priority">Ordered by decreasing priority </param>
    /// <param name="options"></param>
    /// <returns></returns>
    public static string RequireStyle(this IHtmlHelper html, string path, int priority = 1, params string[] options)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_STYLE] as List<ResourceToInclude>;
        if (requiredScripts == null) ctxt.Items[REQ_STYLE] = requiredScripts = new List<ResourceToInclude>();
        if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceToInclude() { Path = path, Priority = priority, Options = options });
        return null;
    }

    /// <summary>
    /// Just call @Html.EmitRequiredStyles()
    /// at the end of your head tag
    /// </summary>
    public static HtmlString EmitRequiredStyles(this IHtmlHelper html)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_STYLE] as List<ResourceToInclude>;
        if (requiredScripts == null) return null;
        StringBuilder sb = new StringBuilder();
        foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
        {
            sb.Append(item.ToString());
        }
        return new HtmlString(sb.ToString());
    }
    #endregion Styles

    #region Models
    public class InlineResource : Resource
    {
        public string Content { get; set; }
        public override string ToString()
        {
            return "<script>"+Content+"</script>";
        }
    }

    public class ResourceToInclude : Resource
    {
        public string Path { get; set; }
        public string[] Options { get; set; }
        public override string ToString()
        {
            switch(Type)
            {
                case ResourceType.CSS:
                    if (Options == null || Options.Length == 0)
                        return String.Format("<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\" />\n", Path);
                    else
                        return String.Format("<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\" {1} />\n", Path, String.Join(" ", Options));
                default:
                case ResourceType.Script:
                    if (Options == null || Options.Length == 0)
                        return String.Format("<script src=\"{0}\" type=\"text/javascript\"></script>\n", Path);
                    else
                        return String.Format("<script src=\"{0}\" type=\"text/javascript\" {1}></script>\n", Path, String.Join(" ", Options));
            }
        }
    }
    public class Resource
    {
        public ResourceType Type { get; set; }
        public int Priority { get; set; }
        public bool Bottom { get; set; }
    }
    public enum ResourceType
    {
        Script,
        CSS
    }
    #endregion Models
}

Meine 2 Cent, es ist ein alter Beitrag, aber immer noch relevant, daher hier ein aktualisiertes Update der Lösung von Mr. Bell, die mit ASP.Net Core arbeitet.

Es ermöglicht das Hinzufügen von Skripts und Stilen zum Hauptlayout aus importierten Teilansichten und Unteransichten sowie das Hinzufügen von Optionen zum Importieren von Skripts/Stilen (z. B. async defer usw.):

public static class ScriptsExtensions
{
    const string REQ_SCRIPT = "RequiredScript";
    const string REQ_STYLE = "RequiredStyle";

    public static string RequireScript(this IHtmlHelper html, string path, int priority = 1, params string[] options)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_SCRIPT] as List<ResourceInclude>;
        if (requiredScripts == null) ctxt.Items[REQ_SCRIPT] = requiredScripts = new List<ResourceInclude>();
        if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority, Options = options });
        return null;
    }


    public static HtmlString EmitRequiredScripts(this IHtmlHelper html)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_SCRIPT] as List<ResourceInclude>;
        if (requiredScripts == null) return null;
        StringBuilder sb = new StringBuilder();
        foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
        {
            if (item.Options == null || item.Options.Length == 0)
                sb.AppendFormat("<script src=\"{0}\" type=\"text/javascript\"></script>\n", item.Path);
            else
                sb.AppendFormat("<script src=\"{0}\" type=\"text/javascript\" {1}></script>\n", item.Path, String.Join(" ", item.Options));

        }
        return new HtmlString(sb.ToString());
    }


    public static string RequireStyle(this IHtmlHelper html, string path, int priority = 1, params string[] options)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_STYLE] as List<ResourceInclude>;
        if (requiredScripts == null) ctxt.Items[REQ_STYLE] = requiredScripts = new List<ResourceInclude>();
        if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority, Options = options });
        return null;
    }


    public static HtmlString EmitRequiredStyles(this IHtmlHelper html)
    {
        var ctxt = html.ViewContext.HttpContext;

        var requiredScripts = ctxt.Items[REQ_STYLE] as List<ResourceInclude>;
        if (requiredScripts == null) return null;
        StringBuilder sb = new StringBuilder();
        foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
        {
            if (item.Options == null || item.Options.Length == 0)
                sb.AppendFormat("<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\" />\n", item.Path);
            else
                sb.AppendFormat("<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\" {1} />\n", item.Path, String.Join(" ", item.Options));
        }
        return new HtmlString(sb.ToString());
    }


    public class ResourceInclude
    {
        public string Path { get; set; }
        public int Priority { get; set; }
        public string[] Options { get; set; }
    }
}
4
Jean

Für diejenigen, die nach der Aspnet Core 2.0-Version suchen:

    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.AspNetCore.Html;
    using Microsoft.AspNetCore.Http;

    public static class HttpContextAccessorExtensions
    {
        public static string RequireScript(this IHttpContextAccessor htmlContextAccessor, string path, int priority = 1)
        {
            var requiredScripts = htmlContextAccessor.HttpContext.Items["RequiredScripts"] as List<ResourceInclude>;
            if (requiredScripts == null) htmlContextAccessor.HttpContext.Items["RequiredScripts"] = requiredScripts = new List<ResourceInclude>();
            if (requiredScripts.All(i => i.Path != path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority });
            return null;
        }

        public static HtmlString EmitRequiredScripts(this IHttpContextAccessor htmlContextAccessor)
        {
            var requiredScripts = htmlContextAccessor.HttpContext.Items["RequiredScripts"] as List<ResourceInclude>;
            if (requiredScripts == null) return null;
            StringBuilder sb = new StringBuilder();
            foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
            {
                sb.AppendFormat("<script src=\"{0}\" type=\"text/javascript\"></script>\n", item.Path);
            }
            return new HtmlString(sb.ToString());
        }
        public class ResourceInclude
        {
            public string Path { get; set; }
            public int Priority { get; set; }
        }
    }

Fügen Sie Ihrem Layout nach dem Aufruf des Skript-Render-Abschnitts Folgendes hinzu:

@HttpContextAccessor.EmitRequiredScripts()

Und aus Ihrer teilweisen Sicht:

@inject IHttpContextAccessor HttpContextAccessor

...

@HttpContextAccessor.RequireScript("/scripts/moment.min.js")
1
Sebastian

Basierend auf der Antwort von Mr. Bell And Shimmy oben, füge ich eine zusätzliche Funktion für das Bundle-Skript hinzu.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Web.Mvc;
namespace ABC.Utility
{
public static  class PartialViewHelper
{
    public static string RequireScript(this HtmlHelper html, string path, int priority = 1)
    {
        var requiredScripts = HttpContext.Current.Items["RequiredScripts"] as List<ResourceInclude>;
        if (requiredScripts == null) HttpContext.Current.Items["RequiredScripts"] = requiredScripts = new List<ResourceInclude>();
        if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority });
        return null;
    }

    public static string RequireBundleStyles(this HtmlHelper html, string bundleName)
    {
        var a = System.Web.Optimization.Styles.Render(bundleName);
        var requiredStyles = HttpContext.Current.Items["RequiredStyles"] as IHtmlString;
        if (requiredStyles == null) HttpContext.Current.Items["RequiredStyles"] = requiredStyles = a;
        return null;
    }

    public static string RequireBundleScripts(this HtmlHelper html, string bundleName)
    {
        var a=System.Web.Optimization.Scripts.Render(bundleName);
        var requiredScripts = HttpContext.Current.Items["RequiredScripts"] as IHtmlString;
        if (requiredScripts == null) HttpContext.Current.Items["RequiredScripts"] = requiredScripts = a;
        return null;
    }

    public static HtmlString EmitRequiredBundleStyles(this HtmlHelper html)
    {
        var requiredStyles = HttpContext.Current.Items["RequiredStyles"] as IHtmlString;
        if (requiredStyles == null) return null;
        return MvcHtmlString.Create(requiredStyles.ToHtmlString()) ;
    }

    public static HtmlString EmitRequiredBundleScripts(this HtmlHelper html)
    {
        var requiredScripts = HttpContext.Current.Items["RequiredScripts"] as IHtmlString;
        if (requiredScripts == null) return null;
        return MvcHtmlString.Create(requiredScripts.ToHtmlString());
    }

    public static HtmlString EmitRequiredScripts(this HtmlHelper html)
    {
        var requiredScripts = HttpContext.Current.Items["RequiredScripts"] as List<ResourceInclude>;
        if (requiredScripts == null) return null;
        StringBuilder sb = new StringBuilder();
        foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
        {
            sb.AppendFormat("<script src=\"{0}\" type=\"text/javascript\"></script>\n", item.Path);
        }
        return new HtmlString(sb.ToString());
    }
    public class ResourceInclude
    {
        public string Path { get; set; }
        public int Priority { get; set; }
    }
}//end class
}// end namespace  

Beispiel für PartialView: - @ Html.RequireBundleStyles ("~/bundles/fileupload/bootstrap/BasicPlusUI/css"); @ Html.RequireBundleScripts ("~/bundles/fileupload/bootstrap/BasicPlusUI/js"); 

Beispiel auf MasterPage: - @ Html.EmitRequiredBundleStyles ()

0
Harris Yer

Sie können eine neue Layout-Seite erstellen und die PartialView in eine Vollansicht einbetten, die für das Rendern des Inhalts und aller Bibliotheksabschnitte verantwortlich ist.

Angenommen, ich habe den folgenden Code:

HomeController.cs

[HttpGet]
public ActionResult About()
{
    var vm = new AboutViewModel();
    return View("About", vm);
}

Wenn die Ansicht "Ganze Seite" gerendert wird, wird sie normalerweise durch das Zusammenführen zweier Dateien gerendert:

About.cshtml

@model AboutViewModel

@{
    ViewBag.Title = "About CSHN";
}

<h3>@ViewBag.Title</h3>

@section Styles {
    <style> /* style info here */ </style>
}

@section Scripts {
    <script> /* script info here */ </script>
}

_Layout.cshtml (oder was auch immer in _ViewStart angegeben oder auf der Seite überschrieben ist)

<!DOCTYPE html>

<html>
<head>
    @RenderSection("Styles", false)
    <title>@ViewBag.Title</title>
</head>
<body>
    @RenderBody()

    @RenderSection("scripts", false)
</body>
</html>

Nun, Sie möchten About.cshtml als Partial View darstellen, möglicherweise als modales Fenster als Antwort auf den Aufruf von AJAX. Das Ziel dabei ist es, nur den in der About-Seite angegebenen Inhalt, die Skripts und alle zurückzuliefern, ohne dass das gesamte _Layout.cshtml-Master-Layout aufgebläht wird (wie ein vollständiges <html>-Dokument).

Sie könnten es so versuchen, aber es wird keine der Abschnittsblöcke enthalten:

return PartialView("About", vm);

Fügen Sie stattdessen eine einfachere Layoutseite wie folgt hinzu:

_PartialLayout.cshtml

<div>
    @RenderBody()
    @RenderSection("Styles", false)
    @RenderSection("scripts", false)
</div>

Oder um ein modales Fenster wie folgt zu unterstützen: 

_ModalLayout.cshtml

<div class="modal modal-page fade" tabindex="-1" role="dialog" >
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">

            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title">@ViewBag.Title</h4>
            </div>

            <div class="modal-body">

                @RenderBody()
                @RenderSection("Styles", false)
                @RenderSection("scripts", false)

            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-inverse" data-dismiss="modal">Dismiss</button>
            </div>
        </div>
    </div>
</div>

Dann können Sie eine benutzerdefinierte Master-Ansicht in diesem Controller oder einem anderen Handler angeben, mit dem Sie den Inhalt und die Scripts einer Ansicht gleichzeitig rendern möchten

[HttpGet]
public ActionResult About()
{
    var vm = new AboutViewModel();
    return !Request.IsAjaxRequest()
              ? View("About", vm)
              : View("About", "~/Views/Shared/_ModalLayout.cshtml", vm);
}
0
KyleMit

Verwenden Sie @using(Html.Delayed()){ ...your content... }-Erweiterungen von answer https://stackoverflow.com/a/18790222/1037948 , um später auf der Seite Inhalte (Skripts oder nur HTML) wiederzugeben. Interne Queue sollte die korrekte Reihenfolge sicherstellen.

0
drzaus

Hier ist meine Lösung für die häufig gestellten Fragen "Wie füge ich Abschnitte von Teilansichten in Hauptansichten oder Hauptlayoutansicht für asp.net mvc ein?". Wenn Sie eine Suche in Stackoverflow nach Schlüsselwörtern "Abschnitt + Teilweise" durchführen, erhalten Sie eine große Liste mit verwandten Fragen und Antworten, aber keine davon erscheint mir durch die Rasierer-Engine-Grammatik elegant. Also schau ich mir die Razor Engine an und finde heraus, ob es eine bessere Lösung für diese Frage gibt.

Glücklicherweise habe ich etwas gefunden, das für mich interessant ist, wie die Razor-Engine die View-Vorlagendatei (* .cshtml, * .vbhtml) kompiliert. (Ich werde später erklären), unten ist mein Code der Lösung, die meiner Meinung nach ziemlich einfach und elegant genug ist.

namespace System.Web.Mvc.Html
{
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// 确保所有视图,包括分部视图(PartialView)中的节(Section)定义被按照先后顺序追加到最终文档输出流中
        /// </summary>
        public static MvcHtmlString EnsureSection(this HtmlHelper helper)
        {
            var wp = (WebViewPage)helper.ViewDataContainer;
            Dictionary<string, WebPages.SectionWriter> sw = (Dictionary<string, WebPages.SectionWriter>)typeof(WebPages.WebPageBase).GetProperty("SectionWriters", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance).GetValue(wp);
            if (!helper.ViewContext.HttpContext.Items.Contains("SectionWriter"))
            {
                Dictionary<string, Stack<WebPages.SectionWriter>> qss = new Dictionary<string, Stack<WebPages.SectionWriter>>();
                helper.ViewContext.HttpContext.Items["SectionWriter"] = qss;
            }
            var eqs = (Dictionary<string, Stack<WebPages.SectionWriter>>)helper.ViewContext.HttpContext.Items["SectionWriter"];
            foreach (var kp in sw)
            {
                if (!eqs.ContainsKey(kp.Key)) eqs[kp.Key] = new Stack<WebPages.SectionWriter>();
                eqs[kp.Key].Push(kp.Value);
            }
            return MvcHtmlString.Create("");
        }

        /// <summary>
        /// 在文档流中渲染指定的节(Section)
        /// </summary>
        public static MvcHtmlString RenderSectionEx(this HtmlHelper helper, string section, bool required = false)
        {
            if (helper.ViewContext.HttpContext.Items.Contains("SectionWriter"))
            {
                Dictionary<string, Stack<WebPages.SectionWriter>> qss = (Dictionary<string, Stack<WebPages.SectionWriter>>)helper.ViewContext.HttpContext.Items["SectionWriter"];
                if (qss.ContainsKey(section))
                {
                    var wp = (WebViewPage)helper.ViewDataContainer;
                    var qs = qss[section];
                    while (qs.Count > 0)
                    {
                        var sw = qs.Pop();
                        var os = ((WebViewPage)sw.Target).OutputStack;
                        if (os.Count == 0) os.Push(wp.Output);
                        sw.Invoke();
                    }
                }
                else if (!qss.ContainsKey(section) && required)
                {
                    throw new Exception(string.Format("'{0}' section is not defined.", section));
                }
            }
            return MvcHtmlString.Create("");
        }
    }
}

usage : Die Verwendung des Codes ist ebenfalls recht einfach und sieht fast genauso aus wie üblich. Es unterstützt auch alle Ebenen zu den verschachtelten Teilansichten. dh. Ich habe eine Ansichtsvorlagenkette: _ViewStart.cshtml-> layout.cshtml-> index.cshtml -> [head.cshtml, foot.cshtml] -> ad.cshtml. 

In layout.cshtml haben wir:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>@ViewBag.Title - @ViewBag.WebSetting.Site.WebName</title>
    <base href="@ViewBag.Template/" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1.0, user-scalable=0,user-scalable=no">
    <meta name="format-detection" content="telephone=no">
    <meta name="renderer" content="webkit">
    <meta name="author" content="Taro Technology Co.,LTD" />
    <meta name="robots" content="index,follow" />
    <meta name="description" content="" />
    <meta name="keywords" content="" />
    <link rel="alternate icon" type="@ViewBag.WebSetting.Site.WebFavIcon" href="@ViewBag.WebSetting.Site.WebFavIcon">
    @Html.RenderSectionEx("Head")
</head>
<body>
    @RenderBody()
    @Html.RenderSectionEx("Foot")
</body>
</html>

Und in index.cshtml haben wir:

@{
    ViewBag.Title = "首页";
}

@Html.Partial("head")
<div class="am-container-1">
    .......
</div>
@Html.Partial("foot")

Und in head.cshtml hätten wir den Code:

@section Head{
    <link rel="stylesheet" href="assets/css/amazeui.css" />
    <link rel="stylesheet" href="assets/css/style.css" />
}

<header class="header">
   ......
</header>
@Html.EnsureSection()

dies ist auch in foot.cshtml oder ad.cshtml der Fall. Sie können immer noch den Head- oder Foot-Abschnitt darin definieren. Stellen Sie sicher, dass Sie @ Html.EnsureSection () einmal am Ende der Teilansichtdatei aufrufen. Das ist alles, was Sie tun müssen, um das betreffende Problem in asp mvc zu beseitigen.

Ich teile einfach mein Code-Snippet, damit andere es nutzen können. Wenn Sie es für nützlich halten, zögern Sie bitte nicht, meinen Post zu bewerten. :)

0
Jonathan

Diese Funktionalität ist auch in ClientDependency.Core.Mvc.dll implementiert. Es bietet die HTML-Helfer: @ Html.RequiresJs und @ Html.RenderJsHere (). Nuget-Paket: ClientDependency-Mvc 

0
Evert