31

注意:我现在创建了一个 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% 是相关的。对我来说,这感觉非常错误,我觉得我应该只执行每页需要的代码,主要是为了效率,也是为了可维护性。

我已经在谷歌搜索了解决这个问题的方法,但找不到任何东西,也许我只是在寻找错误的东西!

无论如何,所以我的问题是:

  • 有没有人想过这个问题?
  • 在其他人看来这真的是一个问题吗?
  • 您的代码中是否有一个大型的、包罗万象的文档就绪处理程序,或者它是否更专注于所服务的页面类型?
  • 如果是后者,您如何管理?在 JS 中切换的多个处理程序或在服务器端动态吐出文档就绪处理程序?

期待人们对此事的看法。

干杯

4

9 回答 9

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>

您几乎可以对其进行调整以使其适用于任何语言。而且这种方法不关心你是有一个文件还是多个文件。

于 2011-09-30T03:59:26.050 回答
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)
});

东西应该是相对可维护的,即使有几十行。在使用组件代码时,在此级别没有需要更新/记住的复杂/有趣的逻辑,并且由于此级别的所有内容都是微不足道的,因此很容易阅读。至此,没有必要发明一些复杂的注册系统;它不会比.delegateand更简单.each

还要注意,以上所有内容都可以优雅地处理不使用组件的情况。在这些情况下,很少或根本不做任何工作,也不需要条件逻辑。

有关如何实现处理程序/初始化程序的有趣想法,您可能想看看,例如,Doug Neiner 上周在 jQuery Boston 上发表的“实践中的上下文 jQuery ”演讲。

于 2011-10-05T02:00:57.270 回答
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.locationDOM 参考:https ://developer.mozilla.org/en/DOM/window.location

于 2011-09-30T03:33:57.147 回答
1

首先,我将特定的类放在主体或特定容器上,例如,、、、articles…… 。如果我有一个 MVC 应用程序,我更喜欢将控制器名称放入 body 类中。这不会造成太大伤害,并且对造型也很有用。form-validationpassword-meter

然后在每个 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
});

这种方法的好处是没有不需要的代码可以潜入就绪回调中,这使得它更容易重用。缺点是你会得到很多回调块,如果你不注意重复代码很容易潜入你的应用程序。

于 2011-10-03T19:47:08.853 回答
0

我知道你从哪里来。正确的移动使用 web 应用程序让用户下载一个充满不相关代码的大量 JS 文件可能会让人觉得很愚蠢(对于一个人来说,JQuery API 是一个糟糕的开始!)。

我所做的,可能是对的,也可能是错的,但似乎确实有效,是在标签之前逐页包含所需的功能。(这个位置大部分是绕过 document.ready 问题)。然而不禁觉得这种做法太简单了。

我有兴趣听到其他答案,所以这是一个很好的问题,+1。

于 2011-09-28T11:07:19.103 回答
0

“问题是我们只有一个 JS 文件”

只要您为所有页面包含相同的(合并的)JS文件,我不确定如何避免它。您可以使用一些服务器端逻辑来合并不同的部分以使用不同的页面,但是您可能会失去 JS 客户端缓存的好处,所以......

我从事的项目(通常)使用了多个 JS 文件,每个页面都有一对,其他的被包含或不包含 - 一些 JS 文件只包含在一个页面中。这意味着几乎每个页面都包含公共库函数,无论它们是否使用它们,但是公共 JS 文件会被缓存,所以这并不重要。特定于页面的代码确实是特定于页面的。

我无法从您的问题中判断您是否意识到这一点,但是您可以拥有多个文档就绪处理程序(我相信 jQuery 会按照绑定的顺序执行它们?)。因此,如果您将 JS 拆分,每个 JS 文件都可以包含自己的文档。当然,这种方法有其自身的开销,但我认为这比将所有内容都放在同一个文件中要好。

于 2011-09-28T11:51:15.367 回答
0

首先,如果您使用 jQuery,则 document.getElementsByTagName 并不是必需的,您可以使用 $("tagname")。查看jQuery Selectors 文档以获得更多魔力!

您正在进行的解决方案是我将要解决的方法,但您无需费心定义额外的函数、获取 bodyClasses、运行循环或任何爵士乐......为什么不只是使用 jQuery 的.hasClass()函数?

$(function() {
    if($("body").hasClass("article")) {
        alert("some article specific code");
    }
    if($("body").hasClass("landingPage")) {
        alert("some landing specific code");
    }
});

巴姆。一切你需要的。如果您想提高效率,可以重用一个正文查询:

$(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/

于 2011-09-29T20:25:01.263 回答
0

拥有更少的 javascript 文件可以最大限度地减少发送到服务器的请求数量,并且缓存文件可以使第二页和第三页加载得更快。通常,我会考虑以下页面(而不仅仅是当前页面)可能需要 js 文件的某些部分。这使我将我的 js 代码分为两种类型:在我的“main.js”中的代码,即使不使用,它也会被客户端下载(但不一定执行,我会解释),以及第二类代码放在单独的文件中。您实际上可以创建多个按概率分组的文件。这取决于您的项目的详细信息。如果它是一个大型项目,对用户行为进行一些统计分析可能会揭示有趣的 js 代码分组方式。现在代码已经下载到客户端,我们不想执行所有这些。你应该做的是有不同的布局或页面。在布局或页面中放置一个部分。在部分内部设置一个 javascript 变量。检索 javascript 代码中的 javascript 变量并确定是否要执行某些代码。

IE:

创建部分“_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
 }
});

我希望这有帮助!

于 2011-10-03T00:05:53.793 回答
0

我喜欢 RameshVel 方法。我还发现了Paloma gem来创建特定于页面的 JavaScript。例如:

Paloma.controller('Admin/Users', {
  new: function(){
    // Handle new admin user
  }
});
于 2017-08-27T21:20:52.783 回答