注意:我现在已经创建了一个jQuery插件,这是我尝试解决此问题的方法。我确信它可以改进,我可能忽略了很多用例,所以如果有人想提供反馈,请随意:-) https://github.com/WickyNilliams/ReadyBinder
我没有这样的问题,但认为这将是一个有趣的讨论点,我希望人们对此有一些有趣的想法。
基本上,我在一个大型网站上工作,我们越来越多地编写越来越多的JavaScript。这很好,我喜欢JS独特的方法,我发现在语言的一些较暗的年代中可爱的奇怪之处;-)然而,一直困扰我的一件事是如何管理文档就绪事件,因为它们变得越来越大随着时间的推移(因此对于所服务的页面不太专注/特定)
问题是我们有一个JS文件(合并和缩小,虽然这对我的问题来说无关紧要)。大多数JS都是使用揭示模块模式编写的,jQuery是我们选择的框架。因此,我们所有的JS功能在逻辑上都分为方法,命名空间,然后在脚本文件的底部,我们有这个
$(function(){
//lots of code here, usually calling encapsulated methods
//on our namespaced revealing module
});
问题在于,并非本文档就绪处理程序中的所有代码都与每个页面相关。例如,在一个页面上只有10%可能是相关的,在另一个页面上,80%可能是相关的。对我来说,这感觉非常错误,我觉得我应该只执行每页所需的代码,主要是为了提高效率,还要保持可维护性。
我搜索谷歌搜索此问题的方法,但找不到任何东西,也许我只是在寻找错误的东西!
无论如何,所以我的问题是:
期待人们对此事的看法。
干杯
答案 0 :(得分:9)
这是我在我的rails mvc项目中用大量的javascript做的,我为js中的控制器创建了一个单独的命名空间,类似于rails控制器
class BusinessController
def new
end
def index
end
end
和
Var Business = {
init : function(action) {
//code common to the Business module
//even add the common jquery doc ready here, its clean
//and call the page specific action
this[action]();
},
new : function() {
// check jquery document ready code here, thats relevant to this action
//New rental page specific code here
},
index : function() {
// check jquery document ready code here, thats relevant to this action
//index rental page specific code here
}
}
并且在视图代码(服务器端)上只需通过
启动页面特定的js代码<script type="text/javascript">
<%= controller_name %>.init('<%= controller.action_name %>');
//which will render to
// Business.init(index);
</script>
你可以调整它以使其适用于任何语言。这种方法并不关心您是单个文件还是多个文件。
答案 1 :(得分:2)
我认为这个问题必须直观的解决方案是减少加载时的工作量。
如果您的代码类似于:
$(function () {
// Binds a single click event (which will never be triggered if the hypothetical
// widget is never used), regardless of how many widgets are used on the page.
$(document).delegate('.rating-widget', 'click', namespace.rating.handler);
// and so on for similar things which simply require event handler registration
// Initializes each of the forms on the page, letting the initializer take care
// of any details (datepicker widgets, validation, etc) based on the root element
$('form.fancy').each(namespace.fancyform.initializer);
// and so on for similar things that require initialization
// ... (for each type of thing on the page requiring initial setup,
// find the most general/high level pattern that sufficient)
});
事情应该是相对可维护的,即使有几十行。在使用组件代码时,此级别没有复杂/有趣的逻辑来更新/记忆,因为这个级别的所有内容都很简单,所以很容易阅读。在这一点上,没有必要发明一些复杂的注册系统;它不会比.delegate
和.each
更简单。
请注意,以上所有内容都可以优雅地处理不使用该组件的情况。在这些情况下,很少或根本没有工作,也没有条件逻辑。
关于如何实现处理程序/初始化程序的有趣想法,您可能需要查看,例如,Doug Neiner上周在jQuery Boston上发表的“Contextual jQuery in practice”演讲。
答案 2 :(得分:1)
好问题。我实际上通过使用自定义页面加载事件来处理这个 所以在我的核心.js文件中,我有一个如下的类:
var Page = {
init: function(pageName) {
switch (pageName)
{
case: 'home': {
// Run home page specific code
}
case: 'about': {
// Run about page specific code
}
...
}
}
}
您可以通过特定于页面的$(document).ready()
或使用某种URL解析器从核心脚本中调用此方法(实际上,使用URL解析器可以实现任何方式):
$(document).ready(function() {
// http://www.mydomain.com/about
var currentPage = window.location.pathname; // "about"
Page.init(currentPage);
});
window.location
DOM参考:https://developer.mozilla.org/en/DOM/window.location
答案 3 :(得分:1)
首先,我将特定的课程放在身体或特定的容器上,例如articles
,form-validation
,password-meter
,....如果我有一个MVC应用程序,我更喜欢将控制器名称放入一个body类。这并没有太大的伤害,也可以用于造型。
然后在每个document.ready块上检查是否存在这样的类,如果它不存在,我将从此函数返回。这种方法更简单,因为它没有if子句中的主代码。这种方法类似于用于检查函数先决条件的断言。
示例:
$(function(){
if($('body').hasClass('articles') === false){ return; }
//body of the articles code
});
$(function(){
if($('body').hasClass('password-meter') === false){ return; }
//include password meter in page
});
这种方法的好处是,没有不需要的代码可以潜入现成的回调,这使得重用更容易。缺点是你得到很多回调块,如果你不注意重复的代码可以很容易地潜入你的应用程序。
答案 4 :(得分:0)
我知道你来自哪里。对于移动使用的正确的webapps,它可能会让用户下载一个充满无关代码的大量JS文件而感到愚蠢(一个JQuery API是一个糟糕的开始!)。
我所做的,可能是对或错,但似乎确实有用,包括在标签之前逐页包含所需的功能。 (大多数情况下,这个位置绕过document.ready问题)。但是不禁觉得这种做法太简单了。
我有兴趣听到其他答案,所以这是一个很好的问题,+ 1。
答案 5 :(得分:0)
“问题是我们有一个JS文件”
只要您为所有页面包含相同(合并)的JS文件,我不确定如何避免它。您可以使用一些服务器端逻辑来合并不同的部分以使用不同的页面,但是您可能会失去JS的客户端缓存的好处,所以......
我曾经参与过的项目(通常)使用了多个JS文件,每个页面都有一对共享,其他包含或不包含在内 - 有些JS文件只包含在一个页面中。这意味着几乎每个页面都包含公共库函数,无论它们是否使用它们,但是常见的JS文件被缓存,因此它并不重要。页面特定的代码确实是特定于页面的。
我无法从你的问题中看出你是否意识到这一点,但是你可以拥有多个文档就绪处理程序(我相信jQuery会按照绑定的顺序执行它们吗?)。因此,如果您将JS拆分起来,每个JS文件都可以包含自己的文档。当然,这种方法有其自身的开销,但我认为这比将所有内容放在同一个文件中更好。
答案 6 :(得分:0)
首先,如果您使用的是jQuery,那么document.getElementsByTagName并不是必需的,您可以使用$(“tagname”)。看看jQuery Selectors documentation更加神奇!
您正在进行的工作解决方案就是我的方法,但您不需要去定义额外的功能,获取bodyClasses,运行循环或任何爵士乐......为什么不直接使用jQuery的.hasClass()函数?
$(function() {
if($("body").hasClass("article")) {
alert("some article specific code");
}
if($("body").hasClass("landingPage")) {
alert("some landing specific code");
}
});
的Bam。一切你需要的。如果您想提高效率,可以重复使用一个正文查询:
$(function() {
var body = $("body");
if(body.hasClass("article")) {
alert("some article specific code");
}
if(body.hasClass("landingPage")) {
alert("some landing specific code");
}
});
这是jsfiddle:http://jsfiddle.net/W8nx8/6/
答案 7 :(得分:0)
拥有较少的javascript文件可最大限度地减少发送到服务器的请求数量,并缓存文件使第二页和第三页加载速度更快。 通常,我想在以下页面(而不仅仅是当前页面)中需要js文件的某些部分的可能性。这使我将我的js代码分为两种类型: 代码进入我的“main.js”,即使没有使用,也会被客户端下载(但不一定要执行,我会解释),第二类代码分别放在不同的文件中。您实际上可以创建按概率分组的多个文件。这取决于项目的详细信息。如果它是一个大型项目,对用户行为进行一些统计分析可能会揭示有趣的方法来分组js代码。 现在代码已下载到客户端,我们不想执行所有代码。 你应该做的是有不同的布局或页面。在布局或页面中放置一个部分。在局部集内设置一个javascript变量。检索javascript代码中的javascript变量,并确定是否要执行某些代码。
即:
创建部分“_stats.html.erb”,将此代码放入其中:
<script type="text/javascript">
var collect_statistics = <%= collect_statistics %>;
</script>
将部分放在您要收集统计信息的页面中: show.html.erb
<%= render "_stats", :collect_statistics => false %>
现在在您的js文件中,执行以下操作:
$(document).load( function() {
if (typeof collect_statistics != "undefined" && collect_statistics) {
// place code here
}
});
我希望这有帮助!
答案 8 :(得分:0)
我喜欢RameshVel方法。我还发现了Paloma gem来创建特定于页面的JavaScript。例如:
Paloma.controller('Admin/Users', {
new: function(){
// Handle new admin user
}
});