What is a clean pattern for keeping all the JavaScript in the bottom of my page?
我们为不同的页面提供了一个嵌套的布局。例如:
1 2 3 4 5 | <!DOCTYPE html> <html> <head>...</head> <body>@RenderBody()<body> </html> |
1 2 3 4 5 | ... lot of stuff ... @Html.Partial("Voting", Model.Votes) <script type="text/javascript"> ... some javascript .. |
1 2 3 4 | ... lot of stuff ... <script type="text/javascript"> ... some javascript .. |
这一切都很好,但我希望在所有内容之后,将所有的javascript块都推送到页面的底部。
有没有一种方法可以在嵌套的部分中定义一个magic指令,使各种脚本标记在页面底部按顺序呈现?
例如,我可以创建一个魔法助手来捕获所有JS块,然后获取顶层布局来呈现它吗?
1 2 3 4 5 6 7 | ... lot of stuff ... @appendJSToFooter{ <script type="text/javascript"> ... some javascript .. } |
大约一年前,我通过创建一个助手来在
在分部中,我按名称注册关联的脚本文件:
1 | @Html.RegisterScript("BnjMatchyMatchy") |
然后在主页上,我调用一个方法来迭代注册的脚本:
1 | @Html.RenderRegisteredScripts() |
这是当前助手:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | public static class JavaScriptHelper { private const string JAVASCRIPTKEY ="js"; public static void RegisterScript(this HtmlHelper helper, string script) { var jScripts = helper.ViewContext.TempData[JAVASCRIPTKEY] as IList<string>; // TODO should probably be an IOrderedEnumerable if (jScripts == null) { jScripts = new List<string>(); } if (!jScripts.Contains(script)) { jScripts.Add(script); } helper.ViewContext.TempData[JAVASCRIPTKEY] = jScripts; } public static MvcHtmlString RenderRegisteredScripts(this HtmlHelper helper) { var jScripts = helper.ViewContext.TempData[JAVASCRIPTKEY] as IEnumerable<string>; var result = String.Empty; if (jScripts != null) { var root = UrlHelper.GenerateContentUrl("~/scripts/partials/", helper.ViewContext.HttpContext); result = jScripts.Aggregate("", (acc, fileName) => String.Format("<script src="{0}{1}.js"" + "type="text/javascript"> ", root, fileName)); } return MvcHtmlString.Create(result); } } |
正如我的托多所指出的(我应该讨论一下),你可以很容易地修改这个,使用一个IORDerenumerable来保证订单。
正如我所说的不完美,输出一堆
我意识到这艘船已经航行了很多次,但由于我有某种解决方案(尽管不是完美的),我想我会分享它。
我写了一篇关于我使用的脚本呈现方法的博客文章。在那篇文章中,我提到了迈克尔·J·瑞安写的一个图书馆,我为自己的目的做了一些调整。
使用这种方法,可以在任何地方使用如下方法呈现脚本:
1 2 3 4 5 6 7 | @Html.AddClientScriptBlock("A script", @" $(function() { alert('Here'); }); ") |
然后在布局页面中,在结束正文标记之前使用此调用触发它的输出:
1 | @Html.ClientScriptBlocks() |
使用此方法在Visual Studio中无法获得IntelliSense。如果我诚实的话,我并不建议使用这种技术;我宁愿为调试点使用单独的JS文件,并使用HTML数据属性来驱动任何动态行为。但如果有用的话,我想我会分享它。空手警告等
以下是相关链接的列表:
如果您遇到的情况是无法改进现有的结构(例如,您有MVC和旧的WebForms页面,所有地方都包含javascript标记等等),那么您可以看看我在一个对输出进行后处理的HTTP模块上所做的一些工作,就像在Apache中所做的mod pagespeed一样。不过还是很早的时候。
https://github.com/teun/resourcecombinator
如果您仍然可以选择以预先定义的方式包含脚本,那可能更好。
编辑:Sam提到的项目(见评论)实际上在很大程度上是重叠的,而且更加成熟。我从Github中删除了ResourceCombinator项目。
这有点老生常谈,但是如果您的目标是对现有视图(除了移动渲染的脚本之外)进行最小的更改,那么我过去所做的方法(特别是在Web表单中,但也适用于MVC)就是用一个将脚本推到底部的方法覆盖
基本上,您只需编写一个
那么HTML响应过滤器呢,它可以修改最终的HTML。在特定位置之前找到所有脚本标记,并将它们粘贴到正文的末尾。它还可以改进数据表的呈现,通过最初将它们标记为隐藏,并让JS显示出来。
不需要对实际代码进行干预或更改。
山姆,
我之所以写门户网站是因为这个原因:http://nuget.org/packages/portal你基本上把
1 | @Html.PortalOut() |
在主视图/布局视图中,从视图或类似的部分视图中填充HTML代码
1 | @Html.PortalIn(@<text> $(function() { alert('Hi'); }); </text>) |
通过指定输入和输出键,可以使用多个"门户"。现在,它按代码的顺序添加代码(先渲染部分,从"上到下")。如果你在同一个视图中,你必须处理从上到下的限制,也就是说,你不能在"in"之前有一个"out"门户,但是从视图发送到布局时这不是一个问题。在portal.cs文件中有更多的示例。
我谦虚的选择是把这类事情留给专业人员:-)看看ControlJS,一个加载外部JavaScript文件的lib,而不中断页面处理(异步、延迟、按需等)。有了ControlJS,您不必介意将加载代码放在"哪里",它们都将在末尾或按需加载。
自由党作者SteveSouders的这篇演讲对这个问题(以及解决方案)进行了很好的概述。
我们使用Telerik(GPL开源)ASP.NET MVC库中的脚本注册器方法。
只需在下面的任何视图/部分页面等中包含您的javascript。Telerik库处理在最终输出页面的底部呈现所有这些内容。
1 2 3 4 5 6 7 | <% Html.Telerik().ScriptRegistrar() .Scripts(scripts => scripts.AddSharedGroup('lightbox') .OnDocumentReady(() => { %> <%-- LIGHTBOX --%> $('.images a').lightBox(); <% });%> |
它还负责将多个CSS和JS包含组合成单个请求。
http://www.telerik.com/products/aspnet-mvc.aspx
我建议你不要把脚本直接放到你的页面上。
相反,将javascript拉到一个单独的.js文件中,然后在头中引用它。
我知道这并不完全是你想要的,但是我假设你这样做是为了SEO的目的,这应该和把脚本放在页面底部有同样的效果。