【问题标题】:Where to put DOM interaction on scalable javascript architecture将 DOM 交互放在可扩展的 JavaScript 架构的什么位置
【发布时间】:2011-12-19 19:49:00
【问题描述】:

目前我对如何拥有更可维护的 JavaScript 架构感到有些困惑。我可能跑题了,但我会说我几乎 50% 的代码涉及 DOM,因此使用我的基础库 (jQuery)。

我查看了 [1] Nicholas Zakas 的可扩展应用程序架构设计:http://developer.yahoo.com/yui/theater/video.php?v=zakas-architecture 和 [2] Addy Osmani Patterns For Large-Scale JavaScript Application Architecture http://addyosmani.com/largescalejavascript/

我有一个单页应用程序样式,通过 ajax 获取大量内容并动态添加 DOM 元素。我的主要问题是:如果我使用 jQuery(或任何其他基础库)来操作 DOM,如何将代码分成可重复使用的小块。

让我们以一个任务列表模块为例。我知道该模块可能如下所示:

var TaskList = function() {
  addTask = function() {
    ...
  };

  removeTask = function() {
    ...
  };

  return {
    addTask: addTask,
    removeTask: removeTask
  }
}();

DOM 元素事件注册应该写在哪里,保存、加载或删除任务的 ajax 调用,将新任务附加到 DOM 元素等。

我没有任何问题承诺将模块上的 jQuery 作为依赖项,但如果有更好的方法,我想我从上面的两个资源中错过了它,我很想知道它。

我只是想用一种更优雅的方式来维护不断增长的 javascript,因为我厌倦了意大利面;)

感谢您的宝贵时间!

【问题讨论】:

    标签: javascript architecture


    【解决方案1】:

    由于您要开发单页应用程序,因此您将拥有许多可视模块,这些模块将在当前步骤中显示,然后它们将被其他模块替换。

    您可以遵循 MVC 模式(模型-控制器-视图),每个可视元素都是一个单独的实体,具有自己的 DOM 操作代码和存储在单独类中的业务逻辑。

    一种方法是:

    <html>
      <head>
       ....
      </head>
      <body>
        <div id="content"> 
        <!--The main container view that can handle the replacement of smaller views -->
          <div id="toolbar"_container">
            <!-- container for menu bar or tool bar that can also has its contained 
                 sub-views replaced -->
          </div>
          <div id="main_content_container">
            ....
          </div>
          <div id="properties_panel">
           .....
          </div>
        </div>      
      </body>
    </html>
    

    主容器可以容纳所有较小的容器,每个人都可以容纳一个不同的视图控制器,它有自己的 DOM 操作代码,(这还具有能够按需动态加载的好处,从而减少了初始化加载时间)。

    每个视图都可以有几个模块来执行“操作”,并与第三个模块(可选)进行通信,该模块将处理数据库、套接字、文件等的 I/O。

    希望对您有所帮助!

    【讨论】:

    • 采用像 knockoutjs 这样启用了 MVVM 的库还可以帮助您以更清晰的 ui 交互方式组织代码。
    • 这几乎就是我在 HTML 结构方面的设置方式。该应用程序已经在生产中。我对javascript atm更感兴趣,从你所说的你建议我创建两个“javascript类”如果我们可以说一个控制器和一个视图并且在视图上有DOM代码是吗?
    【解决方案2】:

    您可以使用Backbone.js 或探索CQRS(和相关模式)以获得更多自定义、复杂和解耦的解决方案。这完全取决于您的应用程序的复杂性(以及潜在的未来增长)。

    您也可以查看some of this posts。在具体示例中,有几个针对您的问题的好方法;)

    【讨论】:

      【解决方案3】:

      保持业务逻辑和显示逻辑分开

      这不仅仅适用于 DOM。浏览器和 Node 中的许多 API 都是围绕触发和侦听事件或等待其他类型的异步工作完成而设计的。一个经验法则是,如果您正在编写大量匿名回调函数,您的代码可能不容易测试。

      // hard to test
      $('button').on('click', () => {
          $.getJSON('/path/to/data')
              .then(data => {
                  $('#my-list').html('results: ' + data.join(', '));
              });
      });
      
      // testable; we can directly run fetchThings to see if it
      // makes an AJAX request without having to trigger DOM
      // events, and we can run showThings directly to see that it
      // displays data in the DOM without doing an AJAX request
      $('button').on('click', () => fetchThings(showThings));
      
      function fetchThings(callback) {
          $.getJSON('/path/to/data').then(callback);
      }
      
      function showThings(data) {
          $('#my-list').html('results: ' + data.join(', '));
      }
      

      在异步代码中使用回调或承诺

      解决这个问题最常见的方法是将回调函数作为参数传递给异步运行的函数。在您的单元测试中,您可以在您传递的回调中运行您的断言。

      // hard to test; we don't know how long the AJAX request will run
      function fetchData() {
          $.ajax({ url: '/path/to/data' });
      }
      
      // testable; we can pass a callback and run assertions inside it
      function fetchDataWithCallback(callback) {
          $.ajax({
              url: '/path/to/data',
              success: callback,
          });
      }
      
      // also testable; we can run assertions when the returned Promise resolves
      function fetchDataWithPromise() {
          return $.ajax({ url: '/path/to/data' });
      }
      

      Here is the details

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-17
        • 2018-01-06
        • 2019-04-01
        • 2016-12-06
        • 2010-12-15
        • 2011-03-12
        • 2013-11-16
        • 1970-01-01
        相关资源
        最近更新 更多