[javascript] 부분에서 Razor 섹션 채우기

이 작업을 수행하는 주된 동기는 부분이 렌더링되는 페이지의 중간이 아니라 나머지 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를 사용하여 부분보기에서 섹션을 채울 수 있습니까? 그렇지 않다면, 페이지 하단의 부분에만 필요한 자바 스크립트를 전역 적으로 포함하지 않고 얻는 다른 방법은 무엇입니까?



답변

이 문제를 처리 한 방법은 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().

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


답변

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


답변

필요한 자바 스크립트 삽입만을 담당하는 두 번째 부분을 가질 수 있습니다. @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")
}

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


답변

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

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


답변

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. 부분 및 템플릿 (보기에 나타나는 순서, 위에서 아래로)

답변

[업데이트 된 버전]
@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; }
    }
}


답변

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