Điền một phần dao cạo từ một phần


102

Động lực chính của tôi khi cố gắng làm điều này là để có được Javascript chỉ được yêu cầu bởi một phần ở cuối trang với phần còn lại của Javascript và không phải ở giữa trang nơi phần đó được hiển thị.

Đây là một ví dụ đơn giản về những gì tôi đang cố gắng làm:

Đây là bố cục với phần Scripts ngay trước phần nội dung.

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

Đây là một chế độ xem ví dụ sử dụng bố cục này.

<h2>This is the view</h2>

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

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

Và đây là một phần được kết xuất từ ​​chế độ xem.

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

Trong ví dụ này, đánh dấu được chỉ định trong dạng xem được đặt vào phần, nhưng đánh dấu từ một phần thì không. Có thể điền một phần từ chế độ xem một phần bằng Razor không? Nếu không, một số phương pháp khác để lấy Javascript mà chỉ cần các thành viên ở cuối trang mà không đưa nó vào toàn cầu là gì?


có thể đó là sự cố vì bạn có một phần tập lệnh khác trong phần .. IDK .. mã của bạn hơi khó hiểu ..
gideon

Nó không thể. Ngay cả khi phần bị bỏ ra khỏi chế độ xem, thì mã trong phần đó không vào được trang được hiển thị cuối cùng. Tôi nghĩ SLaks là đúng khi các thành viên không thể tham gia vào các phần của chế độ xem chính.
Craig M

Câu trả lời:


78

Cách tôi xử lý vấn đề này là viết một vài phương thức mở rộng cho lớp HtmlHelper. Điều đó cho phép các chế độ xem Partals nói rằng chúng yêu cầu một tập lệnh và sau đó trong chế độ xem bố cục ghi thẻ mà tôi gọi đến phương thức trợ giúp của mình để phát ra các tập lệnh bắt buộc

Dưới đây là các phương pháp trợ giúp:

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

Một khi bạn có điều đó tại chỗ, bạn chỉ cần gọi @Html.RequireScript("/Path/To/Script").

Và trong phần đầu của chế độ xem bố cục mà bạn gọi @Html.EmitRequiredScripts().

Một phần thưởng bổ sung của điều này là nó cho phép bạn loại bỏ các yêu cầu tập lệnh trùng lặp. Nếu bạn có nhiều chế độ xem / một phần chế độ xem cần một tập lệnh nhất định, bạn có thể yên tâm giả định rằng bạn sẽ chỉ xuất nó một lần


Giải pháp thanh lịch và sạch sẽ. +1
bevacqua

Chỉ cần đi qua giải pháp này sau khi kéo hầu hết tóc của tôi ra - giải pháp tuyệt vời ....
higgsy

Tôi không thể làm cho giải pháp này hoạt động. Có vẻ như EmitRequiredScripts () được gọi trước khi bất kỳ chế độ xem từng phần nào được gọi đến RequestScript (). Tôi có làm điều gì sai?
Bryan Roth

Có gì đó không ổn, Bryan. Tôi đã sử dụng giải pháp này rộng rãi trong năm qua và nó đang hoạt động tốt. Có thể đăng một câu hỏi mới với các chi tiết về vấn đề của bạn và liên kết url ở đây
Mr Bell

1
Điều này có bất kỳ hỗ trợ chặn bộ nhớ cache nào khi triển khai phiên bản mới của ứng dụng không? Phương thức out-of-box @ scripts.Render () gắn một tham số URL vào cuối được tạo tại thời điểm xây dựng để trình duyệt buộc phải tìm nạp phiên bản mới nhất khi một phiên bản mới được triển khai.
Simon Green

28

Chế độ xem một phần không thể tham gia vào các mục của chế độ xem gốc của chúng.


1
Đây là điều tôi đã nghi ngờ. Cảm ơn.
Craig M

@JohnBubriski Có trong Razor 2. Không biết về máy tính bảng. các phiên bản.
Shimmy Weitzhandler

@SLaks, tại sao điều này là do thiết kế? Trong kịch bản của tôi, tôi có một phần là công cụ quay biểu ngữ, tôi muốn các tập lệnh / kiểu của nó chỉ tải khi nó được bật, tại sao tải nội tuyến lại tệ?
Shimmy Weitzhandler

2
@Shimmy: Bạn nên sử dụng hệ thống quản lý tài nguyên, chẳng hạn như Cassette.
SLaks

Cảm ơn bạn. Tôi sẽ xem xét nó.
Shimmy Weitzhandler

13

Bạn có thể có một phần thứ hai chỉ phụ trách việc đưa các javascript cần thiết vào. Đặt một số tập lệnh vào đó xung quanh @ifcác khối, nếu bạn muốn:

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

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

Điều này rõ ràng có thể được làm sạch một chút, nhưng sau đó, trong Scriptsphần của chế độ xem của bạn:

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

Một lần nữa, nó có thể không giành được giải thưởng sắc đẹp nhưng nó sẽ hoạt động.


1
Điều này khá gần với những gì tôi đã làm. Nó chắc chắn không đẹp, nhưng nó hoạt động. Nhược điểm duy nhất của điều này là bạn không thể lấy một phần thông qua lệnh gọi ajax và có JS đi kèm. Tôi nghĩ về lâu dài, tôi sẽ kết thúc việc tái cấu trúc bằng cách sử dụng các mẫu jQuery và chỉ gửi JSON từ bộ điều khiển của tôi thay vì xây dựng html ở phía máy chủ.
Craig M

@CraigM đó cũng là nơi tôi hướng tới. MVC là hợp pháp, nhưng nó có ý nghĩa hơn (đối với tôi) khi sử dụng các mẫu phía máy khách (tôi đang xem xét Backbone.js) và sau đó đẩy / kéo từ một API.
one.beat.consumer

@ one.beat.customer - Tôi đã sử dụng các mẫu của gạch dưới vì tôi cũng sử dụng Backbone, nhưng tôi đang nghĩ đến việc chuyển sang thư viện Hogan từ Twitter hoặc Plates từ Nodejitsu. Cả hai đều có những tính năng khá đẹp.
Craig M

10

Cách đơn giản hơn để làm điều này là di chuyển các tập lệnh xem từng phần thành tệp riêng biệt và sau đó hiển thị nó trong phần Tập lệnh của chế độ xem:

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

Chế độ xem một phần _ Partial.cshtml :

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

Chế độ xem một phần _ PartialScripts.cshtml chỉ với các tập lệnh:

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

Điều này không tự động như một số phương pháp mở rộng hoặc trình cắm được đề xuất trong các câu trả lời khác, nhưng nó có ưu điểm là đơn giản và rõ ràng. Nó thích nó.
Mark Meuer

7

Cài đặt gói nuget Forloop.HtmlHelpers - nó thêm một số trình trợ giúp để quản lý tập lệnh trong các dạng xem từng phần và các mẫu trình soạn thảo.

Ở đâu đó trong bố cục của bạn, bạn cần gọi

@Html.RenderScripts()

Đây sẽ là nơi bất kỳ tệp tập lệnh và khối tập lệnh nào sẽ được xuất trong trang vì vậy tôi khuyên bạn nên đặt nó sau các tập lệnh chính của bạn trong bố cục và sau một phần tập lệnh (nếu bạn có).

Nếu bạn đang sử dụng Khung tối ưu hóa web với tính năng đóng gói, bạn có thể sử dụng quá tải

@Html.RenderScripts(Scripts.Render)

để phương pháp này được sử dụng để viết ra các tệp kịch bản.

Bây giờ, bất cứ lúc nào bạn muốn thêm tệp script hoặc khối trong một dạng xem, dạng xem một phần hoặc mẫu, chỉ cần sử dụng

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

Người trợ giúp đảm bảo rằng chỉ một tham chiếu tệp tập lệnh được hiển thị nếu được thêm nhiều lần và nó cũng đảm bảo rằng các tệp tập lệnh được hiển thị theo thứ tự dự kiến, tức là

  1. Bố trí
  2. Phân vùng và Mẫu (theo thứ tự xuất hiện trong chế độ xem, từ trên xuống dưới)

5

[Phiên bản cập nhật] Phiên bản cập nhật sau câu hỏi @Necrocubus để Bao gồm các tập lệnh nội tuyến.

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 xu của tôi, đó là một bài đăng cũ, nhưng vẫn còn phù hợp, vì vậy đây là bản cập nhật nâng cấp của giải pháp Mr Bell hoạt động với ASP.Net Core.

Nó cho phép thêm các tập lệnh và kiểu vào bố cục chính từ các chế độ xem từng phần và chế độ xem phụ đã nhập và khả năng thêm các tùy chọn vào nhập tập lệnh / kiểu (như async defer, v.v.):

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

Cảm ơn bạn! Điều này sẽ được ủng hộ nhiều hơn vì nó phù hợp hơn so với câu trả lời đã 6 năm tuổi.
Necroqubus

Ngoài ra, các phần mở rộng này có thể được sửa đổi để cho phép các phần của tập lệnh là đầu vào không? @ <text> </text> hoặc một cái gì đó giống như các phần? Nếu không tôi vẫn cần một kịch bản JS nhỏ để khởi tạo các kịch bản khác với các biến mô hình Server side: /
Necroqubus

@Necroqubus bạn có thể kiểm tra phiên bản cập nhật, tuy nhiên tôi đã không kiểm tra nó chưa :)
Jean

Được rồi, tôi sẽ thử và kiểm tra nó cho bạn. Tôi hy vọng nó hoạt động với ASP.NET Core 1.0 MVC. Đối với ngữ cảnh, tôi có nhiều cấp độ của các phần tử lồng nhau và muốn các tập lệnh của chúng được hiển thị ở chân trang.
Necroqubus

Không cần <text>, chỉ cần thêm nó như là một chuỗi (bạn vẫn có thể tiếp đầu ngữ với @ "" cho đa dòng nếu bạn thích), và không có <script>thẻ
Jean

1

Bạn có thể tạo một Layouttrang mới và bọc PartialView bên trong Chế độ xem đầy đủ chịu trách nhiệm hiển thị nội dung và bất kỳ phần thư viện nào.

Ví dụ: giả sử tôi có mã sau:

HomeController.cs

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

Khi chế độ xem Toàn trang được hiển thị, nó thường được hiển thị bằng cách hợp nhất hai tệp:

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 (hoặc bất cứ điều gì được chỉ định trong _ViewStart hoặc được ghi đè trong trang)

<!DOCTYPE html>

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

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

Bây giờ , giả sử bạn muốn Hiển thị About.cshtmldưới dạng Chế độ xem một phần , có thể là cửa sổ phương thức để phản hồi lệnh gọi AJAX. Mục tiêu ở đây là chỉ trả lại nội dung được chỉ định trong trang giới thiệu, các tập lệnh và tất cả, mà không có tất cả các khối có trong _Layout.cshtmlbố cục chính (như một<html> tài liệu ).

Bạn có thể thử nó như thế này, nhưng nó sẽ không đi kèm với bất kỳ khối phần nào:

return PartialView("About", vm);

Thay vào đó, hãy thêm một trang bố cục đơn giản hơn như sau:

_PartialLayout.cshtml

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

Hoặc để hỗ trợ một cửa sổ phương thức như thế này:

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

Sau đó, bạn có thể chỉ định Chế độ xem chính tùy chỉnh trong bộ điều khiển này hoặc bất kỳ trình xử lý nào khác mà bạn muốn hiển thị đồng thời nội dung và tập lệnh của chế độ xem

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

1

Đối với những người đang tìm kiếm phiên bản aspnet core 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; }
        }
    }

Thêm vào bố cục của bạn sau cuộc gọi phần hiển thị tập lệnh:

@HttpContextAccessor.EmitRequiredScripts()

Và theo quan điểm một phần của bạn:

@inject IHttpContextAccessor HttpContextAccessor

...

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

0

Dựa trên câu trả lời từ Mr Bell And Shimmy ở trên, tôi thêm chức năng bổ sung cho tập lệnh 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  

Mẫu trên PartialView: - @ Html.RequireBundleStyles ("~ / packles / fileupload / bootstrap / BasicPlusUI / css"); @ Html.RequireBundleScripts ("~ / packles / fileupload / bootstrap / BasicPlusUI / js");

Mẫu trên MasterPage: - @ Html.EmitRequiredBundleStyles ()


0

Sử dụng @using(Html.Delayed()){ ...your content... }tiện ích mở rộng từ answer https://stackoverflow.com/a/18790222/1037948 để hiển thị bất kỳ nội dung nào (tập lệnh hoặc chỉ HTML) sau này trong trang. Nội bộ Queuenên đảm bảo đúng thứ tự.


0

Chức năng này cũng được triển khai trong ClientDependency.Core.Mvc.dll. Nó cung cấp các trình trợ giúp html: @ Html.RequiresJs và @ Html.RenderJsHere (). Gói Nuget: ClientDependency-Mvc


0

Đây là giải pháp của tôi cho các câu hỏi thường gặp "làm thế nào để đưa các phần từ dạng xem một phần sang dạng xem chính hoặc dạng xem bố cục chính cho asp.net mvc?". Nếu bạn thực hiện tìm kiếm trên stackoverflow theo từ khóa "phần + một phần", bạn sẽ nhận được một danh sách khá lớn các câu hỏi liên quan và câu trả lời cho sẵn, nhưng không có câu nào trong số đó có vẻ thanh lịch đối với tôi bằng ngữ pháp công cụ dao cạo. Vì vậy, tôi chỉ cần xem xét động cơ Razor để xem liệu có thể có giải pháp nào tốt hơn cho câu hỏi này không.

May mắn thay, tôi đã tìm thấy một điều thú vị đối với tôi về cách công cụ Razor thực hiện biên dịch cho tệp mẫu chế độ xem (* .cshtml, * .vbhtml). (Tôi sẽ giải thích sau), dưới đây là mã của tôi về giải pháp mà tôi nghĩ là khá đơn giản và đủ thanh lịch trong cách sử dụng.

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

sử dụng : Để sử dụng mã này cũng khá đơn giản và nó trông gần như giống kiểu thông thường. Nó cũng hỗ trợ bất kỳ cấp độ nào đối với các chế độ xem từng phần lồng nhau. I E. Tôi có một chuỗi mẫu xem: _ViewStart.cshtml-> layout.cshtml-> index.cshtml -> [head.cshtml, foot.cshtml] -> ad.cshtml.

Trong layout.cshtml, chúng ta có:

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

Và trong index.cshtml, chúng ta có:

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

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

Và trong head.cshtml, chúng tôi sẽ có mã:

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

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

nó giống nhau trong foot.cshtml hoặc ad.cshtml, bạn vẫn có thể xác định phần Head hoặc Foot trong chúng, hãy đảm bảo gọi @ Html.EnsureSection () một lần ở cuối tệp xem từng phần. Đó là tất cả những gì bạn cần làm để loại bỏ vấn đề chủ thể trong asp mvc.

Tôi chỉ chia sẻ đoạn mã của mình để những người khác có thể sử dụng nó. Nếu bạn cảm thấy nó hữu ích, xin đừng ngần ngại tăng xếp hạng bài viết của tôi. :)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.