2011-03-18 98 views
92

我試圖做到這一點的主要動機是獲得只有頁面底部的部分與Javascript的其餘部分所需的JavaScript,而不是在頁面中間部分被渲染。從部分填充剃刀部分

這裏是什麼,我試圖做一個簡單的例子:

這裏是與身體前右一腳本部分的佈局。

<!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從部分視圖中填充一個部分?如果沒有,還有其他一些獲得Javascript的方法,只有頁面底部的partials才需要,而不用全局包含它?

+0

也許它的一個問題,因爲你在部分.. IDK中有另一個腳本部分..你的代碼有點令人困惑.. – gideon 2011-03-18 17:18:00

+0

這不是。即使該部分不在視圖中,部分中的代碼也不會將其放入最終呈現的頁面中。我認爲SLaks是正確的,因爲partials不能參與父視圖的部分。 – 2011-03-18 19:10:02

回答

75

我處理這個問題的方法是向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()

這是一個額外的好處是,它允許你刪除重複的腳本請求。如果您有多個需要給定腳本的視圖/部分視圖,則可以安全地假定您只會輸出一次

+4

+1爲體面的工作。 – 2012-02-03 20:32:01

+0

偉大的工作!非常有幫助...謝謝 – 2012-02-08 13:16:54

+0

優雅乾淨的解決方案。 +1 – bevacqua 2012-02-18 22:44:22

26

部分視圖無法參與其父視圖的部分。

+1

這是我懷疑的。謝謝。 – 2011-03-18 19:18:14

+6

但是沒有錯誤?看起來像一個奇怪的行爲... – 2011-09-30 21:50:06

+0

@JohnBubriski有在剃刀2.不知道關於prev。版本。 – Shimmy 2012-11-26 10:18:44

12

你可以有第二個部分只負責注入必要的javascript。將幾個腳本中有沒有解決@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模板進行重構,並從我的控制器發送JSON而不是在服務器端構建html。 – 2011-03-29 17:07:30

+0

@CraigM這也是我領導的地方。 MVC是合法的,但它對於使用模板客戶端(我正在研究Backbone.js)然後從API推入/拉取更有意義。 – 2012-02-03 20:31:20

+0

@ one.beat.customer - 我一直在使用下劃線的模板,因爲我也使用Backbone,但是我正在考慮從Twitter或者Nodejitsu切換到Hogan庫。兩者都有相當不錯的功能。 – 2012-02-07 17:14:12

8

更優雅的方法是將部分視圖腳本移動到單獨的文件中,然後將其呈現在腳本中的視圖部分:

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

局部視圖_ 部分。CSHTML

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

局部視圖_ PartialScripts.cshtml只有腳本:

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

這不像其他答案中提出的某些擴展方法或插件那樣自動,但它確實具有簡單和清晰的優點。它喜歡它。 – 2014-02-14 19:24:35

0

此基礎上,從貝爾先生和擺振上面的答案,我想補充上捆綁腳本的額外功能。

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( 「〜/捆綁/文件上傳/引導/ BasicPlusUI/CSS」); @ Html.RequireBundleScripts(「〜/ bundles/fileupload/bootstrap/BasicPlusUI/js」);

樣品的母版: - @ Html.EmitRequiredBundleStyles()

7

安裝Forloop.HtmlHelpers nuget包 - 它添加了一些輔助工具來管理部分視圖和編輯器模板中的腳本。

在佈局

某處,你需要調用

@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. 局部模板和模板(在它們出現在視圖中,從上到下的順序)
0

此功能也在ClientDependency.Core.Mvc.dll中實現。它提供了html助手:@ Html.RequiresJs和@ Html.RenderJsHere()。 NuGet包:ClientDependency-MVC

3

[更新版] 以下@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的核心工作。

它允許進口部分意見和子視圖,並可能添加腳本和樣式主要佈局添加到腳本/風格的進口選項(如異步推遲等):

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

謝謝你的男人!這應該是更高的,因爲它比6歲的答案更有意義。 – Necroqubus 2017-08-26 19:50:02

+0

另外,可以修改這些擴展以允許輸入腳本的各個部分嗎? @或類似的部分?否則,我仍然需要一個小的JS腳本來初始化其他腳本與服務器端模型變量:/ – Necroqubus 2017-08-26 20:02:51

+0

@Necroqubus你可以檢查更新的版本,但我還沒有測試過它:) – Jean 2017-08-26 21:04:45