#25:组织起来!

到目前为止,我们已经在组织方面做得相当不错。将我们的 HTML 分解成模板是一个很大的进步。我们可以说,我们不再混淆视听。我们在 JavaScript 中的不同功能部分被分解成独立的部分,使它们更容易理解和维护。我知道我们一直在使用一个相当小的演示,但我希望你能想象,随着应用程序变得越来越复杂,代码行数越来越多,这种组织将变得非常宝贵。

JavaScript 对组织没有“意见”。这可能是有些人喜欢它,而有些人却感到迷茫的原因。你如何选择组织它完全取决于你。这也是为什么有些人真正喜欢框架的原因,框架,无论有意见与否,都提供了一个组织结构。例如,Backbone。但这又是另一个系列了!

对于我们的演示,我们只需围绕一个我们创建的对象进行组织。

var Movies = {

}

我们在这里做的所有事情都与在页面上获取一些电影相关,因此我们将把它包含在一个名为 Movies 的“东西”中。请记住,我们只是在做对我们来说组织上有意义的事情。这样做的好处是,也只在“全局范围”中放置了一个变量。如果我们把所有事情都放在全局范围,那将是一团糟,不小心覆盖了在其他地方声明的变量(以及函数等等)。

但是,像这样的对象实际上并不能“做”任何事情。我们需要“启动它”。

var Movies = {

  init: function() {

  }

}

Movies.init();

有一个名为 init 的函数有点像标准,它可以让任何阅读这段代码的人知道,其中的代码是在执行这组代码时运行的。这应该读起来有点像这组代码发生的事情的目录。然后,我们创建其他函数(Movies 对象的更多属性),这些函数执行我们需要完成的任务,分成独立的块。请记住,我们可以随意命名东西,只要对我们有意义就行。

var Movies = {
 
  init: function() {
    this.setUpTemplate();
    this.getData();
    this.bindUIActions();
  },
  
  setUpTemplate: function() {
    // Templating here
  },
  
  getData: function() {
    // Data getting here 
  },
  
  appendMoviesToPage: function(data) {
    // Display logic here
  },
  
  bindUIActions: function() {
    // Event delegating binding here.
  }
  
}

Movies.init();

很清楚吧?你可能会注意到 appendMovesToPage 没有在 init 中调用。这是因为在我们有数据发送给它之前,我们不能调用它。这些数据将来自一个 Ajax 调用,这意味着我们需要一个回调函数。所以 getData 最终会调用那个函数。

这里将要填充的任何其他内容都只是将我们已经编写过的代码片段移动到正确的位置。

var Movies = {
 
  init: function() {
    this.setUpTemplate();
    this.getData();
    this.bindUIActions();
  },
  
  setUpTemplate: function() {
    Movies.compiled = _.template(
      "<div class='module module-movie' style='background-image: url(<%= movieImage %>)'>" + 
        "<div class='movie-info'>" +
          "<h3 class='movie-title'>" +
             "<%= movieTitle %>" + 
          "</h3>" +
          "<p class='movie-director'>" + 
             "<%= movieDirector %>" + 
          "</p>" + 
        "</div>" + 
      "</div>"
    );
  },
  
  getData: function() {
    $.getJSON("http://codepen.io/chriscoyier/pen/0b21d5b4f7fbf4e7858b2ffc8890e007.js", function(data) {
       Movies.appendMoviesToPage(data);
    }); 
  },
  
  appendMoviesToPage: function(data) {
    var i, html = "";
    for (i = 0; i < data.movies.length; i++) {
      html += Movies.compiled(data.movies[i]);
    }  
    $("#movies").append(html);
  },
  
  bindUIActions: function() {
    $(document).on("click", ".module-movie", function() {
      alert("movie added");
    });
  }
  
}

Movies.init();

完成了。

让我们看看我们之前概述的四个问题,看看我们对它们做了什么。

  1. **获取数据。** 我们将 JSON 放到一个我们可以用 $.getJSON 访问的文件中,因为这在真实情况下很可能需要这样做。除了练习这一点,它还允许我们围绕它编写测试。
  2. **显示逻辑。** 我们现在有一个非常具体的函数 appendMoviesToPage,当我们准备好将电影附加到页面时会调用它。单一用途函数非常适合(同样)组织、可理解性和可维护性。
  3. **事件处理。** 使用事件委托,我们不再将这种“业务逻辑”与显示逻辑或模板混合在一起。我们甚至不必担心源代码执行顺序,因为我们最终将事件附加到 document 上。无论模板何时/如何附加到页面,我们的功能都将起作用。
  4. **模板。** 完全迁移到专门用于模板的库。

我认为那是胜利。这就是我们的最终结果

查看 CodePen 上 Chris Coyier (@chriscoyier) 的作品 BwbhI