부분에서 Razor 섹션 채우기


102

이 작업을 수행하는 주된 동기는 부분이 렌더링되는 페이지의 중간이 아니라 나머지 Javascript와 함께 페이지 하단의 부분에만 필요한 Javascript를 얻는 것입니다.

다음은 내가하려는 작업의 간단한 예입니다.

다음은 본문 바로 앞에 Scripts 섹션이있는 레이아웃입니다.

<!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>

다음은이 레이아웃을 사용하는보기의 예입니다.

<h2>This is the view</h2>

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

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

그리고 여기 뷰에서 렌더링되는 부분이 있습니다.

<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>
}

이 예에서 뷰에 지정된 마크 업은 섹션에 배치되지만 부분의 마크 업은 배치되지 않습니다. Razor를 사용하여 부분보기에서 섹션을 채울 수 있습니까? 그렇지 않다면, 페이지 하단의 부분에만 필요한 자바 스크립트를 전역 적으로 포함하지 않고 얻는 다른 방법은 무엇입니까?


부분에 다른 스크립트 섹션이 있기 때문에 문제 일 수 있습니다. IDK .. 코드가 약간 혼란 스럽습니다 ..
gideon

그렇지 않습니다. 섹션이 뷰에서 제외 되더라도 부분의 코드는 최종 렌더링 페이지로 만들지 않습니다. 부분이 상위 뷰의 섹션에 참여할 수 없다는 점에서 SLaks가 정확하다고 생각합니다.
Craig M

답변:


78

이 문제를 처리 한 방법은 HtmlHelper 클래스에 몇 가지 확장 메서드를 작성하는 것입니다. 이를 통해 부분보기에서 스크립트가 필요하다고 말한 다음 필요한 스크립트를 내보내기 위해 도우미 메서드에 호출하는 태그를 작성하는 레이아웃보기에서

도우미 메서드는 다음과 같습니다.

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; }
}

일단 당신이 그 자리에 있으면 부분보기는 @Html.RequireScript("/Path/To/Script").

그리고 레이아웃보기의 헤드 섹션에서 @Html.EmitRequiredScripts().

이것의 추가 보너스는 중복 스크립트 요청을 걸러 낼 수 있다는 것입니다. 주어진 스크립트가 필요한 여러보기 / 부분보기가있는 경우 한 번만 출력한다고 안전하게 가정 할 수 있습니다.


우아하고 깨끗한 솔루션. +1
bevacqua 2012

내 머리카락의 대부분을
빼낸 후에이

이 솔루션이 작동하지 않습니다. 부분 뷰가 RequireScript ()를 호출하기 전에 EmitRequiredScripts ()가 호출되는 것 같습니다. 내가 뭘 잘못하고 있니?
Bryan Roth 2011

뭔가 이상하게 들리 네요, 브라이언. 이 솔루션을 지난 1 년 동안 광범위하게 사용했으며 잘 작동했습니다. 문제에 대한 세부 정보가 포함 된 새 질문을 게시하고 여기에 URL을 연결하십시오.
Mr Bell

1
새 버전의 앱을 배포 할 때 캐시 무효화 지원이 있습니까? 기본 @ scripts.Render () 메서드는 빌드시 생성되는 URL 매개 변수를 끝에 고정하므로 새 버전이 배포 될 때 브라우저가 최신 버전을 가져 오도록 강제합니다.
Simon Green

28

부분보기는 상위보기 섹션에 참여할 수 없습니다.


1
이것이 내가 의심 한 것입니다. 감사.
Craig M

@JohnBubriski Razor 2에 있습니다. 이전에 대해 모릅니다. 버전.
Shimmy Weitzhandler 2011

@ SLaks, 왜 이것이 의도적으로 설계된 것입니까? 내 시나리오에서 배너 회전자인 부분이 있는데 스크립트 / 스타일이 켜져있을 때만로드되기를 원하는데, 인라인으로로드하는 것이 왜 나쁜가요?
Shimmy Weitzhandler 2011

2
@Shimmy : Cassette와 같은 리소스 관리 시스템을 사용해야합니다.
SLaks

감사합니다. 조사하겠습니다.
Shimmy Weitzhandler 2011

14

필요한 자바 스크립트 삽입만을 담당하는 두 번째 부분을 가질 수 있습니다. @if원하는 경우 블록 주위에 여러 스크립트를 배치하십시오 .

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

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

이것은 분명히 약간 정리할 수 있지만 Scripts뷰 섹션 에서 다음과 같습니다.

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

다시 말하지만, 뷰티 상을받지 못할 수도 있지만 작동 할 것입니다.


1
이것은 내가 한 일과 매우 가깝습니다. 확실히 예쁘지는 않지만 작동합니다. 이것의 유일한 단점은 ajax 호출을 통해 부분을 얻을 수없고 JS가 포함되어 있다는 것입니다. 장기적으로는 jQuery 템플릿을 사용하여 리팩토링하고 서버 측에서 html을 빌드하는 대신 컨트롤러에서 JSON을 보낼 것이라고 생각합니다.
Craig M

@CraigM은 내가 향하고있는 곳이기도합니다. MVC는 합법적이지만 클라이언트 측 템플릿 (Backbone.js를 살펴보고 있음)을 사용한 다음 API에서 푸시 / 풀하는 것이 훨씬 더 합리적입니다.
one.beat.consumer 2012

@ one.beat.customer-Backbone도 사용하고 있기 때문에 밑줄 템플릿을 사용해 왔지만 Twitter에서 Hogan 라이브러리로 전환하거나 Nodejitsu에서 Plates로 전환 할 생각입니다. 둘 다 꽤 좋은 기능을 가지고 있습니다.
Craig M

10

이를 수행하는 더 우아한 방법은 부분보기 스크립트를 별도의 파일로 이동 한 다음보기의 스크립트 섹션에서 렌더링하는 것입니다.

<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>
}

부분보기 _ Partial.cshtml :

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

스크립트 만 있는 부분보기 _ PartialScripts.cshtml :

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

이것은 다른 답변에서 제안한 일부 확장 방법 또는 플러그인만큼 자동적이지는 않지만 단순성과 명확성의 이점이 있습니다. 좋아.
Mark Meuer 2014

7

Forloop.HtmlHelpers 너겟 패키지를 설치하십시오 -부분보기 및 편집기 템플릿에서 스크립트를 관리하기위한 일부 도우미를 추가합니다.

레이아웃 어딘가에 전화해야합니다.

@Html.RenderScripts()

이것은 모든 스크립트 파일과 스크립트 블록이 페이지에 출력되는 곳이므로 레이아웃의 기본 스크립트 뒤와 스크립트 섹션 뒤에 넣는 것이 좋습니다 (있는 경우).

번들링과 함께 웹 최적화 프레임 워크를 사용하는 경우 오버로드를 사용할 수 있습니다.

@Html.RenderScripts(Scripts.Render)

이 방법은 스크립트 파일을 작성하는 데 사용됩니다.

이제보기, 부분보기 또는 템플릿에 스크립트 파일이나 블록을 추가하려면 언제든지

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

헬퍼는 여러 번 추가 된 경우 하나의 스크립트 파일 참조 만 렌더링되도록하고 스크립트 파일이 예상 된 순서로 렌더링되도록합니다.

  1. 나열한 것
  2. 부분 및 템플릿 (보기에 나타나는 순서, 위에서 아래로)

5

[업데이트 된 버전] @Necrocubus 질문에 따라 인라인 스크립트를 포함하도록 업데이트 된 버전입니다.

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
}

내 2 센트, 그것은 오래된 게시물이지만 여전히 관련성이 있으므로 여기에 ASP.Net Core와 함께 작동하는 Mr Bell의 솔루션의 업그레이드 된 업데이트가 있습니다.

가져온 부분보기 및 하위보기에서 기본 레이아웃에 스크립트와 스타일을 추가하고 스크립트 / 스타일 가져 오기에 옵션을 추가 할 수 있습니다 (예 : 비동기 지연 등).

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; }
    }
}

고마워요! 6 년된 답변보다 관련성이 더 높기 때문에 더 많이 찬성해야합니다.
Necroqubus

또한 이러한 확장을 수정하여 스크립트 섹션을 입력 할 수 있습니까? @ <text> </ text> 또는 섹션과 같은 것? 그렇지 않으면 나는 아직도 서버 측 모델의 변수를 다른 스크립트를 초기화 작은 JS 스크립트가 필요합니다 /
Necroqubus

@Necroqubus 업데이트 된 버전을 확인할 수 있지만 아직 테스트하지 않았습니다. :)
Jean

좋습니다. 테스트 해 보겠습니다. ASP.NET Core 1.0 MVC에서 작동하기를 바랍니다. 컨텍스트를 위해 여러 수준의 중첩 부분이 있으며 해당 스크립트가 바닥 글에 렌더링되기를 원합니다.
Necroqubus

는 필요하지 않고 <text>문자열로 추가하고 (원하는 경우 여러 줄에 대해 @ ""접두사를 사용할 수 있음) <script>태그 없이
Jean

1

Layout페이지를 만들고 콘텐츠 및 라이브러리 섹션 렌더링을 담당하는 전체보기 내에서 PartialView를 래핑 할 수 있습니다 .

예를 들어 다음 코드가 있다고 가정 해 보겠습니다.

HomeController.cs

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

전체 페이지보기가 렌더링되면 일반적으로 두 파일을 병합하여 렌더링됩니다.

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 (또는 _ViewStart에 지정되거나 페이지에서 재정의 된 모든 것)

<!DOCTYPE html>

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

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

이제 , 당신이 렌더링 싶어한다고 가정 About.cshtmlA와 부분보기 아마 AJAX 호출에 응답하여 모달 창으로. 여기서의 목표 _Layout.cshtml는 전체 <html>문서 와 같이 마스터 레이아웃 에 모든 부풀림이 포함되지 않고 정보 페이지, 스크립트 및 모두에 지정된 콘텐츠 만 반환 하는 것 입니다.

다음과 같이 시도해 볼 수 있지만 섹션 블록은 제공되지 않습니다.

return PartialView("About", vm);

대신 다음과 같이 더 간단한 레이아웃 페이지를 추가하십시오.

_PartialLayout.cshtml

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

또는 다음과 같은 모달 창을 지원하려면 :

_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>

그런 다음 이 컨트롤러 또는 의 내용과 스크립트를 동시에 렌더링하려는 다른 핸들러에서 사용자 정의 마스터 뷰지정할 수 있습니다.

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

1

aspnet 코어 2.0 버전을 찾는 사람들을 위해 :

    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; }
        }
    }

스크립트 렌더링 섹션 호출 후 레이아웃에 추가하십시오.

@HttpContextAccessor.EmitRequiredScripts()

그리고 부분보기에서 :

@inject IHttpContextAccessor HttpContextAccessor

...

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

0

위의 Mr Bell And Shimmy의 답변을 바탕으로 Bundle 스크립트에 대한 추가 기능을 추가합니다.

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  

PartialView의 샘플 :-@ Html.RequireBundleStyles ( "~ / bundles / fileupload / bootstrap / BasicPlusUI / css"); @ Html.RequireBundleScripts ( "~ / bundles / fileupload / bootstrap / BasicPlusUI / js");

MasterPage의 샘플 :-@ Html.EmitRequiredBundleStyles ()



0

이 기능은 ClientDependency.Core.Mvc.dll에서도 구현됩니다. html 도우미를 제공합니다 : @ Html.RequiresJs 및 @ Html.RenderJsHere (). Nuget 패키지 : ClientDependency-Mvc


0

여기에 "asp.net mvc에 대한 부분보기에서 기본보기 또는 기본 레이아웃보기로 섹션을 삽입하는 방법"에 대한 자주 묻는 질문에 대한 솔루션이 있습니다. "section + partial"이라는 키워드로 stackoverflow를 검색하면 관련 질문 목록이 상당히 많이 표시되고 답변이 제공되지만 면도기 엔진 문법을 사용하여 나에게 우아하게 보이는 것은 없습니다. 그래서 저는 Razor 엔진을 살펴보고이 질문에 대한 더 나은 해결책이 있는지 확인합니다.

다행히도 Razor 엔진이 뷰 템플릿 파일 (* .cshtml, * .vbhtml)을 컴파일하는 방법에 대해 흥미로운 점을 발견했습니다. (나중에 설명하겠습니다), 아래는 사용법이 매우 간단하고 우아하다고 생각하는 솔루션 코드입니다.

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("");
        }
    }
}

사용법 : 코드를 사용하는 것도 매우 간단하고 평소와 거의 같은 스타일로 보입니다. 또한 중첩 된 부분보기에 대한 모든 수준을 지원합니다. 즉. 보기 템플릿 체인이 있습니다 : _ViewStart.cshtml-> layout.cshtml-> index.cshtml-> [head.cshtml, foot.cshtml]-> ad.cshtml.

layout.cshtml에는 다음이 있습니다.

<!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>

그리고 index.cshtml에는 다음이 있습니다.

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

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

그리고 head.cshtml에는 다음과 같은 코드가 있습니다.

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

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

foot.cshtml 또는 ad.cshtml에서도 동일합니다. 여전히 Head 또는 Foot 섹션을 정의 할 수 있습니다. 부분보기 파일의 끝에서 @ Html.EnsureSection ()을 한 번 호출해야합니다. asp mvc에서 해당 문제를 제거하기 위해 필요한 모든 것입니다.

다른 사람들이 사용할 수 있도록 내 코드 스 니펫을 공유합니다. 유용하다고 생각되면 주저하지 말고 내 게시물을 평가하십시오. :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.