我想知道在局部视图中包含javascript文件的最佳实践是什么。呈现后,这将最终成为我页面html中间的js include标签。从我的角度来看,这不是执行此操作的好方法。它们属于head标签,因此不应阻止浏览器一次性呈现html。
一个例子: 我在“ PictureGallery”局部视图中使用一个jQuery picturegallery插件,因为该局部视图将在多个页面上使用。仅在使用此视图时加载该插件,并且我不需要知道每个局部视图正在使用哪些插件...
感谢您的回答。
我想知道在局部视图中包含javascript文件的最佳实践是什么。呈现后,这将最终成为我页面html中间的js include标签。从我的角度来看,这不是执行此操作的好方法。它们属于head标签,因此不应阻止浏览器一次性呈现html。
一个例子: 我在“ PictureGallery”局部视图中使用一个jQuery picturegallery插件,因为该局部视图将在多个页面上使用。仅在使用此视图时加载该插件,并且我不需要知道每个局部视图正在使用哪些插件...
感谢您的回答。
Answers:
似乎与以下问题非常相似:在用户控件中链接JavaScript库
我将在此处重新发布该问题的答案。
绝对要出于您提到的原因,建议您不要将它们放入部分中。一个视图很有可能会拉入两个都引用同一个js文件的部分。在加载其余html之前,还具有加载js的性能优势。
我不了解最佳做法,但我选择在母版页中包含所有常见的js文件,然后为一些特定于特定视图或少量视图的其他js文件定义一个单独的ContentPlaceHolder。
这是一个示例母版页-这很容易解释。
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<head runat="server">
... BLAH ...
<asp:ContentPlaceHolder ID="AdditionalHead" runat="server" />
... BLAH ...
<%= Html.CSSBlock("/styles/site.css") %>
<%= Html.CSSBlock("/styles/ie6.css", 6) %>
<%= Html.CSSBlock("/styles/ie7.css", 7) %>
<asp:ContentPlaceHolder ID="AdditionalCSS" runat="server" />
</head>
<body>
... BLAH ...
<%= Html.JSBlock("/scripts/jquery-1.3.2.js", "/scripts/jquery-1.3.2.min.js") %>
<%= Html.JSBlock("/scripts/global.js", "/scripts/global.min.js") %>
<asp:ContentPlaceHolder ID="AdditionalJS" runat="server" />
</body>
Html.CSSBlock和Html.JSBlock显然是我自己的扩展,但同样,它们在做什么方面也很能说明问题。
然后说一个SignUp.aspx视图
<asp:Content ID="signUpContent" ContentPlaceHolderID="AdditionalJS" runat="server">
<%= Html.JSBlock("/scripts/pages/account.signup.js", "/scripts/pages/account.signup.min.js") %>
</asp:Content>
HTH,查尔斯
附言 这是我询问的有关最小化和串联js文件的跟进问题:快速或在构建时串联和缩小JS-ASP.NET MVC
编辑:根据我的其他答案的要求,我对.JSBlock(a,b)的实现
public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName)
{
return html.JSBlock(fileName, string.Empty);
}
public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName, string releaseFileName)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException("fileName");
string jsTag = string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>",
html.MEDebugReleaseString(fileName, releaseFileName));
return MvcHtmlString.Create(jsTag);
}
然后魔术发生了...
public static MvcHtmlString MEDebugReleaseString(this HtmlHelper html, string debugString, string releaseString)
{
string toReturn = debugString;
#if DEBUG
#else
if (!string.IsNullOrEmpty(releaseString))
toReturn = releaseString;
#endif
return MvcHtmlString.Create(toReturn);
}
您将脚本放在页面底部的原因是,在尝试进行任何操作之前,请确保已加载dom。这也可以通过$(document).ready(callback);之类的东西来实现。jQuery方法。
我同意不要将嵌入式JavaScript放在html中的观点。相反,我使用HTML助手来创建一个空div用作服务器指令。辅助信号是Html.ServerData(String name,Object data);
我使用此ServerData方法获取从服务器到客户端的指令。div标记保持其干净,并且“ data-”属性为有效的html5。
对于loadScript指令,我可以在ascx或aspx中执行以下操作:
<%= Html.ServerData(“ loadScript”,新的{url:“ pathTo.js”})%>
或添加另一个帮助程序来使它看起来更干净:
<%= Html.LoadScript(“〜/ path / to.js”)%>
html输出为:
<div name =“ loadScript” data-server =“编码的json字符串”>
然后,我有一个jQuery方法,可以找到任何服务器数据标签:$(containsElement).serverData(“ loadScript”); //返回一个类似jQuery的JSON解码对象数组。
客户端可能看起来像这样:
var script = $(containselement“)。serverData(” loadScript“); $ .getScript(script.url,function(){ //脚本已加载-现在可以执行脚本 });
该技术非常适合需要在ajax加载的内容中加载的用户控件或脚本。我写的版本涉及处理缓存脚本,因此每个完整页面加载它们仅加载一次,并且包含回调和jQuery触发器,因此您可以在准备就绪时将其挂钩。
如果有人对此功能的完整版本(从MVC到jQuery扩展)感兴趣,我很乐意更详细地展示这种技术。否则-希望它为解决这个棘手问题的人提供了一种新方法。
今天,我创建了自己的解决方案,非常适合该法案。无论是好的设计,还是由大家决定,但我认为应该以任何一种方式分享!
以下是我的HtmlExtensions类,该类允许您在母版页中执行此操作:
<%=Html.RenderJScripts() %>
我的HtmlExtensions类:
public static class HtmlExtensions
{
private const string JSCRIPT_VIEWDATA = "__js";
#region Javascript Inclusions
public static void JScript(this HtmlHelper html, string scriptLocation)
{
html.JScript(scriptLocation, string.Empty);
}
public static void JScript(this HtmlHelper html, string scriptLocationDebug, string scriptLocationRelease)
{
if (string.IsNullOrEmpty(scriptLocationDebug))
throw new ArgumentNullException("fileName");
string jsTag = "<script type=\"text/javascript\" src=\"{0}\"></script>";
#if DEBUG
jsTag = string.Format(jsTag, scriptLocationDebug);
#else
jsTag = string.Format(jsTag, !string.IsNullOrEmpty(scriptLocationRelease) ? scriptLocationRelease : scriptLocationDebug);
#endif
registerJScript(html, jsTag);
}
public static MvcHtmlString RenderJScripts(this HtmlHelper html)
{
List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
string result = string.Empty; ;
if(jscripts != null)
{
result = string.Join("\r\n", jscripts);
}
return MvcHtmlString.Create(result);
}
private static void registerJScript(HtmlHelper html, string jsTag)
{
List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
if(jscripts == null) jscripts = new List<string>();
if(!jscripts.Contains(jsTag))
jscripts.Add(jsTag);
html.ViewContext.TempData[JSCRIPT_VIEWDATA] = jscripts;
}
#endregion
}
到底是怎么回事?
上面的类将使用方法扩展HtmlHelper,以将javascript链接添加到该集合所存储的HtmlHelper.ViewContext.TempData
集合中。在母版页的末尾,我将放置<%=Html.RenderJScripts() %>
,它将在内循环jscripts集合HtmlHelper.ViewContext.TempData
并将其呈现到输出中。
但是有一个缺点。.您必须确保在添加脚本之前不呈现脚本。例如,如果要对css链接执行此操作,将无法正常工作,因为您必须将它们放置在<head>
页面的标签中,并且htmlhelper会在甚至添加链接之前呈现输出。
这似乎是一个类似的(尽管不是完全)问题。 返回包含javascript的部分视图是不好的做法吗?
我的偏好是创建一个从您的主Site.master继承的plugin.master页面。想法是,将这些插件填充到plugin.master中,并制作8个左右的页面,这些页面将使用此局部视图从plugin.master继承。
因此,这是一个古老的问题,但是我在尝试解决最近的问题时发现了它。我问了一个问题,并在这里回答了。这是该答案的副本。它类似于OP的答案,但是避免使用TempData。
一种解决方案是实现Html帮助程序扩展功能,该功能只会加载一次脚本。见下文。(这也适用于CSS和其他包含的文件)。
为HtmlHelper类和一个私有支持类实现一个扩展,作为每个HttpContext的单例。
public static class YourHtmlHelperExtensionClass
{
private class TagSrcAttrTracker
{
private TagSrcAttrTracker() { }
public Dictionary<string, string> sources { get; } = new Dictionary<string, string>();
public static TagSrcAttrTrackerInstance {
get {
IDictionary items = HttpContext.Current.Items;
const string instanceName = "YourClassInstanceNameMakeSureItIsUniqueInThisDictionary";
if(!items.Contains(instanceName))
items[instanceName] = new TagSrcAttrTracker();
return items[instanceName] as TagSrcAttrTracker;
}
}
}
public static MvcHtmlString IncludeScriptOnlyOnce(this HtmlHelper helper, string urlOfScript)
{
if(TagSrcAttrTracker.Instance.sources.ContainsKey(urlOfScript))
return null;
TagSrcAttrTracker.Instance.sources[urlOfScript] = urlOfScript;
TagBuilder script = new TagBuilder("script");
scriptTag.MergeAttribute("src", urlOfScript);
return MvcHtmlString.Create(script.ToString());
}
}
然后,将JavaScript和其他代码分离到单独的文件中。
示例.js文件内容
class MyClass{
myFunction() {
constructor(divId){
this._divId = divId
}
doSomething() {
// do something with a div with id == divId
}
}
}
用于部分视图的示例.cshtml文件内容
<link rel="stylesheet" type="text/css" href="~/Content/CustomCSS/MyPartialView.css"/>
<div id="@ViewBag.id">
Some content! Yay!
</div>
@Html.IncludeScriptOnlyOnce("/Scripts/CustomScripts/MyPartialView.js")
使用部分视图的示例.cshtml文件
...
<body>
<h1>Here is some content!</h1>
@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })
@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })
@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_3"} })
</body>
<script>
$().ready(
const id1Functionality = new MyClass("id_1") // forgive the poor naming :-)
const id2Functionality = new MyClass("id_3")
const id3Functionality = new MyClass("id_2")
id1Functionality.doSomething();
id2Functionality.doSomething();
id3Functionality.doSomething();
)
</script>
部分视图可能已经被包含多次,并且JavaScript与部分视图打包在一起,但是.js文件仅包含在页面中一次,因此浏览器不会抱怨MyClass被声明了多次。
MVC的设计人员经历了很多麻烦,阻止了我们使用代码隐藏,但是通过创建名为<viewname> .aspx.cs的文件并相应地修改aspx页面的继承属性,仍然有可能获得它们。
我想说,放置包含的最佳位置是在代码背后的Page_Load处理程序中(使用Page.ClientScript.RegisterClientScriptInclude)。
RegisterClientScriptInclude
从.aspx文件调用吗?还是在期间必须调用它PageLoad
?