跳到主要内容

按顺序获取JavaScript

在我的上一篇文章回到2011年8月,我讨论了一种用于在网站构建中模块化CSS的方法。在此后续工作中,我将介绍一种模块化JavaScript的方法,以便您和您的团队更容易开发和维护。这不是你能做到这一点的唯一方法,但它是一种一直在为我工作的方法 - 而且你在试图组织项目时也会发现它很有用。

最近的浏览器大战似乎过去几年都集中在JavaScript性能上,而且我们使用的内容比以往任何时候都多。我们正在进入一个时代,我们将使用越来越多的客户端脚本来处理传统上被视为服务器端的东西,例如使用JS模板引擎来呈现HTML。考虑到这一点,我认为现在比以前更好地组织JavaScript更重要。

在我们开始之前,我认为值得说明我不是一个铁杆JavaScript程序员。我是一名具有设计背景的前端开发人员,尽管我确实希望提高我的JavaScript技能。这个解决方案诞生于试图让我的生活更轻松,所以希望它可以为你做同样的事情。

我的老方法

在网站上越来越多地使用越来越多的JavaScript的过去几年中,我已经通过相当多的方法来组织我的JavaScript,我对它们中的任何一个都没有完全满意。

Before and after shots of disorganised and well-structured JavaScript folders

在无组织且结构良好的JavaScript文件夹之前和之后拍摄

我使用的常用方法包括一个主要方法的application.js,一堆插件JavaScript文件,一个JavaScript库文件(通常是jQuery),然后,为了使事情更容易阅读,一些功能往往最终分裂成不同的JavaScript文件。这通常会留下一个混乱,看起来令人困惑的JavaScript文件夹。

这一切似乎都不是问题,而这一切都在我的记忆中。但是六个月之后,当我不得不试着回想起我在开发时的想法时,这将是一项艰巨的任务。

通常每个函数都会有一些代码来检查是否存在某些元素,以便决定是否运行函数的其余部分。大多数情况下,这些功能都会寻找一个事件 - 通常点击。所以,像:

if($(“#features”)。length> 0){$(“#features a”)。click(function(e){// do something});}

最初我在DOM就绪函数中根据需要编写了JavaScript。这很快变得难以理解,我记得有一个JavaScript文件长达数千行,并且不得不去看它。

当我意识到这个系统被证明有点笨拙时,我就开始在DOM之外拥有我需要的所有功能,只需在DOM中调用它们即可。我认为这会有所帮助,但它只创建了一些长文件,并使我的所有变量和函数都公开。

这很好,直到我开始为AOL工作,这需要所有JavaScript都在命名空间对象中。这随后让我了解了它们是什么以及如何与它们合作。以这种方式了解对象,属性和方法是尝试加强我的JavaScript游戏的动力。

我渐渐喜欢命名空间对象方法。它内部的每个函数都是一个私有函数,除了一些返回的公共方法和一个准备好在其中启动的DOM在里面()功能。这恰好是我为减少我编写的JavaScript数量所做的努力,更多地依赖于更好的HTML,更新的CSS方法和更简单的交互。我开始意识到我的交互方式过于复杂,仅仅因为我可以。

Slider behaviour JavaScript file: triggers a plug-in with some options. One day I might release the slider plug-in – I use it on nearly every site I build

滑块行为JavaScript文件:触发带有一些选项的插件。有一天,我可能会发布滑块插件 - 我几乎在我构建的每个网站上都使用它

随着浏览器更好地处理JavaScript以及我正在构建的网站的需求增加,我开始再次编写越来越多的JavaScript。这就是使用一个大型JavaScript文件的问题再次出现的时候。更糟糕的是,我经常发现我使用过的任何其他开发人员只是简单地将全局可用的函数放在我的nice命名空间对象之外,因为它对它们来说更简单,更容易。这使我漂亮的JavaScript文件变得丑陋。

当您阅读本我如何组织JavaScript的帐户时,您可能会对如何组织JavaScript进行一些相似之处。一般这些的application.js文件正在增长,并且越来越难以阅读和维护。

我目前的做法

在与一群开发人员合作的同时,也很轻松Pivotal Labs在纽约,我看到了一种新的更好的方法。虽然看起来我的名字有所下降,但我提到Pivotal Labs承认我在哪里看到这种方法。我偷了它。 (好吧,你可以把这个男人从曼彻斯特带出来,但不是曼彻斯特人。)至少我正在做尊敬的事并与你分享。

这种方法的结果是一个更清晰,更具逻辑性的JavaScript目录。所有JavaScript现在都分成了逻辑文件夹结构中的不同文件,用于函数,插件,模板和供应商提供的JavaScript。您可以自己为构建提供更合理的结构,但这就是我现在构建它的方式:

  • 行为是网站需要的DOM交互点。
  • 模板是一个放置JavaScript渲染引擎模板的地方(Mustache,Dust等)。
  • 插件是我为应用程序编写任何JavaScript插件的地方。
  • 供应商用于保存库文件 - 这里是jQuery和我不会更新的任何社区插件。

然后,我不是使用DOM就绪事件来触发检查页面上的元素并在找到它们时执行某些操作的函数,而是使用不同的方法将所有内容连接起来。我实际使用的是需要函数的元素的属性,然后查找该属性以触发函数。我是这样做的:

HTML

具有与之关联的JS功能的DOM元素正在获得数据行为属性,带有方法名称。在这种情况下它是滑块

...

行为JavaScript文件

这种方法的JavaScript存在于/ JS /行为/目录。我给文件名提供与HTML中的行为名称相同的标题。这样可以跟踪它并随着流程的进行更加简单地关注各个元素。这是静态构建的一点,当我的健忘症变得更好,我通常忘记更新HTML以包含这个新的JavaScript文件,然后想知道为什么它不起作用。但是在我的Rails 3应用程序中,它是自动完成的,尽管您可能需要更新应用程序中包含的资源。这对我这样的心不在焉的人来说非常有帮助。

这个新的JavaScript文件是我编写任何我希望与DOM元素交互的JavaScript的地方,在这种情况下看起来像这样:

DLN.Behaviors.slider = function(container){container.slider({sliderInner:container.find(“。features_list”),slideAmount:990,itemsVisible:1,currentSet:1,budge:0,looping:true,quickLinks: false,speed:250,selfCentering:false,paginatorClassname:“features_paginator”,keyControls:true,onMoveFunction:false});};

此行为会触发一个名为的插件滑块,住在/ JS /插件/目录并将一些选项传递给它,其中容器是来自DOM的元素数据行为

应用程序JavaScript

为了调用这些方法并将容器元素传递给它们,我们首先需要构造对象并创建它们的新实例。为此,我们来看看我的的application.js

var DLN = window.DLN || {}; DLN.Behaviors = {}; DLN.LoadBehavior = function(context){if(context === undefined){context = $(document);} context.find(“* [data-behavior]”)。 each(function(){var that = $(this); var behavior = that.attr('data-behavior'); $ .each(behavior.split(“”),function(index,behaviorName){try {var BehaviorClass = DLN.Behaviors [behaviorName]; var initializedBehavior = new BehaviorClass(that);} catch(e){// No Operation}});});}; DLN.onReady = function(){DLN.LoadBehavior() ;}; $(document).ready(function(){DLN.onReady();});

那么这件事发生了什么的application.js?让我们以更近的细节来探索我一直在做的事情。对于这个结构,我们需要一个名称空间对象来存储我们的方法。所以我设置了一个对象,DLN,和行为使用一些文字符号在其中的对象:

var DLN = window.DLN || {};}; DLN.Behaviors = {};

DLN它只是项目名称的初始化,因此您不必使用它。只需将其更改为适合您工作的任何内容。

可以在将来添加命名空间对象内的新对象 - 可能用于模板,辅助函数或其他任何对象,具体取决于项目所需的内容。

在DOM就绪时,JavaScript运行一个名为的方法OnReady反过来,运行LoadBehavior的方法:

DLN.onReady = function(){DLN.LoadBehavior();}; $(document).ready(function(){DLN.onReady();});

LoadBehavior的设置有关查找具有属性的任何元素的DOM数据行为

context.find(“* [data-behavior]”)。each(function(){...}

当它找到具有此属性的元素时,它首先将所讨论的元素存储到一个变量中,该变量又存储一个内容的字符串。数据行为属性:

var that = $(this); var behavior = that.attr('data-behavior');

将元素存储在允许元素稍后传递到目标行为的变量中,并且是一种绕过范围更改的常用方法,当事实证明这不是您想要或期望的那样。我们都去过那里......

This section needs some JavaScript applying to it – so it names the function it wants to call so that it's easy to see what function runs on what

这部分需要一些JavaScript应用它 - 所以它命名它想要调用的函数,以便很容易看到什么函数运行在什么

使用jQuery,它遍历行为名称,拆分成一个数组分裂(” ”)。这很有用,因此一个DOM元素可以有多个行为:

$ .each(behavior.split(“”),function(index,behaviorName){...}

要运行所需的方法,请在...试着抓声明,我们将动态选择的行为克隆到变量中(BehaviorClass)然后制作一个实例(InitializedBehavior),通过具有的元素数据行为属性(这变成了容器在行为JS文件中):

尝试{var BehaviorClass = DLN.Behaviors [behaviorName]; var initializedBehavior = new BehaviorClass(that);}

你可能已经观察到我没有抓住在那试着抓声明 - 可能是一件相当顽皮的事情。但是,如果不存在适当的行为方法,这确实提供了一种不产生错误的方法。

这可能听起来比用手指跟踪代码并简单地解决正在发生的事情更复杂。在这个阶段,熟悉面向对象的JavaScript是有用的。大胡子的Octo文章'OO JS在15分钟或更短时间内完成'是理解编写面向对象的JavaScript的绝佳资源。

Here you will see what happens when application JavaScript sets up objects and calls behaviour methods on document ready

在这里,您将看到当应用程序JavaScript设置对象并在文档就绪时调用行为方法时会发生什么

阿贾克斯

您可能还注意到有一个上下文参数LoadBehavior的功能。这是为了让你运行LoadBehavior的在你已经被放置到位的元素上,而不仅仅是在DOM准备好的元素。你只需要传递你想要的元素LoadBehavior的搜索功能,它也会在ajaxed内容上设置行为。例如:

DLN.LoadBehavior($( “#ajaxed”));

范围

行为本身以及您创建的命名空间对象中的任何其他对象都是全局可用的。因此,您可以从另一个行为调用一个行为,或设置全局可用变量。在这个例子中,运行滑块从您可以调用的不同行为中进行操作:

DLN.Behaviors.slider($( “#newElementNeedsSlider”));

除非您选择,否则行为JS文件中的方法和属性不可全局使用。为了使它们可以将它们定义为行为对象的属性或方法,所以在行为文件中你可以定义:

DLN.Behavior.slider.active = true;。

然后,您可以从您网站上的任何其他JavaScript获取此信息。或者,您可能希望使用全局可访问的getter和setter函数,您可以使用类似的方法设置它们。所以JavaScript的行为可能是:

DLN.Behaviors.slider = function(container){var slide_amount = 13; DLN.Behaviors.slider.setSlideAmount = function(amount){slide_amount = amount; } DLN.Behaviors.slider.getSlideAmount = function(){return slide_amount; } // ...}

现在,您可以通过以下方式全局更新和检索方法的私有变量:

DLN.Behaviors.slider.getSlideAmount(); // 13DLN.Behaviors.slider.setSlideAmount(1312); DLN.Behaviors.slider.getSlideAmount(); // 1312

或者,要使属性或方法全局可用,您只需将其添加到顶级对象:

DLN.version =“1.3.1.2”;

要么:

DLN.error = function(msg){alert(“error!”+ msg);};

请注意,不要太难以遵循定义的位置并最终使这个简单的方法变得复杂。如果要将很多站点范围的变量和函数存储起来,请考虑将对象放入其中,并使用逻辑命名的JavaScript文件夹来包含它们。

生产现场

对于开发,许多带有代码的JS文件都可以。但是对于生产,将它们连接并缩小为一个文件。资产包装工是必须的,否则您将有单独的请求减慢您的应用程序的负载。 Rails 3内置了这种功能,类似的资产包装程序可用于大多数应用程序框架。一个快速的谷歌回复了大量关于压缩JS的建议,比如Rails 3.1资产管道缩小YUI压缩机对于.NET。

谢谢Ross Bruniges他对本教程的同行评审

找到35个顶级Javascript的例子在我们的姐妹网站Creative Bloq。



翻译字数超限