你如何在整个网站上组织大型JS / jQuery代码库?

时间:2010-09-08 14:05:26

标签: javascript jquery

如何在整个网站上组织大型JS / jQuery代码库?关于如何组织代码片段有很多很好的资源,但没有真正关于如何将它们整合在一起并使每个部分适合到位:侧面广泛的代码组织,使用相同代码的多个页面,保持松散耦合的DRY,等

以下是我如何处理它。我从来都不习惯像这样组织我的代码,因为我认为它很草率并且可能导致可维护性/扩展问题,但我真的不知道更好。

我意识到我每个人都有自己的要求而且没有交钥匙的解决方案,但是我很想听到一些关于我做错了什么的意见,为什么我做错了,以及关于如何做错的建议编写更易于维护的代码。

我认为我真正想要的是:

  1. 你如何处理你的逻辑? 需要在多个地方使用 多页?

  2. 如何整理特定于页面的内容 码?将每个页面命名为 一个好主意的全球对象?1。

  3. 从一开始你做什么 确保你不会经常 重写你的组织 随着您的应用变得越来越大 更大?我可能在第四天 迭代写这个东西.2。

  4. 每个页面都会收到主application.js文件。每个额外的页面都有自己的 application.pagename.js文件。我使用服务器端逻辑来包含文件(首先检查看看 如果一个页面甚至存在 - 一些页面不需要JS),然后按顺序初始化它们。

    所以我的主页看起来像:

    <script src="js/application.js"></script>
    <script src="js/application.index.js"></script>
    <script>
        MyApp.init();
        MyApp.index.init();
    </script>
    

    我的网址约为/ page / subpage / id /。我有大约10页和一大堆子页面,每个子页面都需要自己的逻辑。请参阅这篇文章的最后一个例子。

    我的大多数代码已经模块化为jQuery UI小部件或jQuery插件,所以我要说这些文件中有75%的代码需要()来创建一个小部件并启动它。

    我根据需要使用requireJS来拉入小部件。

    // application.js
    var MyApp = {
        init: function(){
            var self = this;
    
            // these widgets are available on every single page
            // notice the call to jquery.deparam.js - i'll use this later to init subpage logic.
            require(['js/widget1.js', 'js/widget2.js', 'js/widget3.js', 'js/jquery.deparam.js'], function(){
    
                // deparam the query string.  I'll use this later.
                self.querystring = $.deparam.querystring();
    
                // init widgets once the document is ready
                $(function(){
                    $("#widget1").widget1();
                    $("#widget2").widget2();
    
                    // make these bindings available immediately as well.
                    self.rebindable();
                });
            });
        },
    
        // I use jQuery UI Dialog extensively as a window manager, and each dialog is loaded
        // via an AJAX request.  I'll call this method after each AJAX request to
        // rebind some key widgets.
        rebindable: function(){
            $("#widget3").widget3();
        }
    };
    
    // application.index.js
    // home page specific stuff.  this file is only included on the home page.
    MyApp.index = {
    
        // my convention is that init is automatically called after the script
        // is included in a page, outside of a doc.ready statement.
        init: function(){
            var self = this;
    
            require(['js/widget4.js'], function(){
                $(function(){
                    self.widget4( $("#foo") );
                });
            });
        },
    
        // passing elements to each method allows me to call this init code
        // outside of the index page.  I can require() this file, and only init
        // widget4, and even use a different element.
        widget4: function( element ){
            var config = {
                something: "custom to the home page"
            };
    
            element.widget4( config );
        }
    };
    
    
    // application.foo.js
    // page "foo" stuff
    MyApp.foo = {
    
        init: function(){
            var self = this;
    
            // this page happens to use the same widget3 and configuration present 
            // in MyApp.index.  this is where things can get sloppy and unmaintainable
            // really quickly.
            require(['js/application.index.js'], function(){
                $(function(){
                    MyApp.index.widget3( $("#bar") );
                });
            });
    
            // page "foo" has three subpages (or actions) and require
            // their own logic.  url convention:  /foo/subpage1/
            // init whichever page we're on...
            switch( self.querystring.subpage ){
                case "subpage1":
                    self.subpage1.init();
                    break;
                case "subpage2":
                    self.subpage2.init();
                    break;
                case "subpage3":
                    self.subpage3.init();
                    break;
            }
        },
    
        subpage1: function(){
            init: function(){
                var self = this;
    
                // once the DOM is ready init dialog.
                $(function(){
                    self.dialog( $("#openDialog") );
                });
            },
    
            dialog: function( element ){
                element.bind("click", function(){
                    $('<div></div>').dialog({
                        open: function(){
    
                            // see what i'm doing here?
                            MyApp.rebindable();
    
                            // maybe more bindings specific to this
                            // dialog here
                        }
                    });
                });
            }
        },
    
        subpage2: function(){
            init: function(){
            }
        },
    
        subpage3: function(){
            init: function(){
            }
        }
    };
    

1 个答案:

答案 0 :(得分:12)

为了帮助我回答您的具体问题,请允许我谈谈JavaScriptMVC的一些功能:

控制器将改进您的jQuery小部件,负责设置/拆卸,可扩展性。

查看会添加可在您的应用中构建的客户端模板。

模型抽象服务/数据层,在服务器更改时最小化和本地化JS更改。

Steal 执行依赖项管理,压缩和代码清理。它甚至可以覆盖所有页面中的所有脚本,找出共享的依赖关系,并将脚本组合成最佳的有效负载。

FuncUnit 可让您的应用尽可能轻松地进行测试。

DocumentJS ......嗯...记录您的代码

现在就您的具体问题:

如何处理多个地方使用的逻辑?

我使用StealJS的依赖管理系统将我需要的功能加载到我的页面中。对于特定大小的应用程序,依赖管理是绝对必要的。如果你能够轻松地构建它,RequireJS是一个不错的选择。

如何整理特定于页面的代码

页面特定代码应尽可能小。它通常涉及加载依赖项和“MainController”。该主控制器将页面配置为遵守该页面的功能/业务要求。它通常被命名为:

App.Controllers.Main

你如何停止编写相同的模式

好吧,我建议使用一个具有稳定模式进行开发的框架。此外,尽可能保持模块/插件/小部件的小(和可测试)。这将使这些部分更改的可能性更小。

最后......

这似乎是你最大的斗争紧张关系:

  • 共享功能
  • 多页
  • 及时加载时间

因此选择一个可靠的依赖管理工具是非常关键的。 StealJS可以帮助您获得非常佳的加载时间,但由于页面数量较多,您必须偏离JavaScriptMVC的标准文件夹组织。

RequireJS更灵活,但您将不得不加载大量文件。这不仅会很慢,而且会开始让你创建大量不太有条理的大JS文件。

如果您对加载时间感到满意并且觉得它们不会导致您将代码压缩到不属于的文件中,那么您当前的解决方案似乎会起作用。

我认为可维护开发的秘诀在于您的系统/框架可以轻松地隔离问题。将应用程序分解为尽可能小的部分非常重要。另外,您应该测试这些部件。人们通过思考他们的页面功能来获得侧面跟踪。但是要真正扩展开发,你真的需要一些东西,它允许你将应用程序分解成很小的部分,轻松加载这些部分,并以某种方式使应用程序仍然在生产中快速运行。