[英]Include JavaScript file in partial views
我想知道在部分视图中包含 javascript 文件的最佳实践是什么。 一旦呈现,这将最终成为我页面 html 中间的一个 js 包含标记。 从我的角度来看,这不是一个很好的方法。 它们属于 head 标签,因此不应阻止浏览器一次性渲染 html。
一个例子:我在“PictureGallery”部分视图中使用了一个 jquery 图片库插件,因为这个部分视图将在几个页面上使用。 这个插件只需要在使用这个视图时加载,我不想知道每个局部视图正在使用哪些插件......
感谢您的回答。
似乎与这个问题非常相似: Linking JavaScript Libraries in User Controls
我会在这里重新发布我对那个问题的回答。
由于您提到的原因,我绝对建议不要将它们放入部分中。 一个视图很可能会引入两个都引用同一个 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 helper 创建一个空 div 用作服务器指令。 helper sig 是 Html.ServerData(String name, Object data);
我使用这个 ServerData 方法来获取从服务器到客户端的指令。 div 标签保持干净,“data-”属性是有效的 html5。
对于 loadScript 指令,我可以在 ascx 或 aspx 中做这样的事情:
<%= Html.ServerData("loadScript", new { url: "pathTo.js" }) %>
或者添加另一个助手来执行此操作,它看起来更简洁:
<%= Html.LoadScript("~/path/to.js") %>
html 输出将是:
<div name="loadScript" data-server="encoded json string">
然后我有一个 jQuery 方法可以找到任何服务器数据标签: $( containsElement).serverData("loadScript"); // 返回一个类似 jQuery 的解码 json 对象数组。
客户端可能看起来像这样:
var script = $(containingelement").serverData("loadScript"); $.getScript(script.url, function () { // script has been loaded - can do stuff with it now });
这种技术非常适合需要在 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() %>
的末尾,我放置了<%=Html.RenderJScripts() %>
,它将在HtmlHelper.ViewContext.TempData
循环 jscripts 集合并将它们呈现到输出。
但是,有一个缺点,.. 您必须确保在添加脚本之前不渲染它们。 例如,如果您想对 css 链接执行此操作,则它不会起作用,因为您必须将它们放在页面的<head>
标记中,并且 htmlhelper 会在您添加链接之前呈现输出。
海迪格
玩弄 Aspnetmvc3 我决定,现在,只将我的 javascript 文件包含在部分
<script src="@Url.Content("~/Scripts/User/List.js")" type="text/javascript"></script>
这个 js 文件特定于我的 /user/List.schtml 文件。
/的
所以,这是一个老问题,但我在尝试解决最近的问题时发现了它。 我在这里问了一个问题并回答了它。 这是该答案的副本。 它类似于 OP 的答案,但避免使用 TempData。
一种解决方案是实现一个 Html helper 扩展函数,它只会加载一次脚本。 见下文。 (这也适用于 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 被多次声明。
这似乎是一个类似(尽管不完全)的问题。 返回包含 javascript 的部分视图是不好的做法吗?
我的偏好是创建一个从您的主 Site.master 继承的 plugin.master 页面。 这个想法是你把这些插件塞进 plugin.master 并制作 8 个左右的页面,这些页面将使用这个部分视图从 plugin.master 继承。
首选方法是将脚本放在底部,但是,如果您无法避免这种情况,那么将它们放在中间是合理的。
浏览器通常并行加载各种页面元素,但是,当浏览器正在下载 Javascript 文件时,它不会并行下载任何其他页面元素,直到 Javascript 下载完成。 这意味着您的图像和其他内容将不得不等待,因此通常认为将脚本移动到底部会更好,但如果您的脚本很小,那么我不会担心。
MVC的设计者费了好大劲才阻止我们使用code-behinds,但是通过创建一个名为<viewname>.aspx.cs的文件,并相应地修改aspx页面的inherits属性,还是可以得到的.
我想说,放置包含的最佳位置是代码隐藏中的 Page_Load 处理程序(使用 Page.ClientScript.RegisterClientScriptInclude)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.