JavaScript中的模型 - 视图 - 控制器

问题描述:

tl; dr:如何在JavaScript中以干净的方式实现MVC?JavaScript中的模型 - 视图 - 控制器

我想在JavaScript中实现MVC。我已经无数次地用我的代码进行了搜索和重组,但没有找到合适的解决方案。 (该代码只是不“感觉正确”。)

下面是我现在正在做的事情。这是非常复杂的,并且是一个痛苦的工作(但仍然比我之前的一堆代码更好)。它具有丑陋的解决方法,这种方式可以击败MVC的目的。

不料,乱七八糟的,如果你真的勇敢:

// Create a "main model" 
var main = Model0(); 

function Model0() { 
    // Create an associated view and store its methods in "view" 
    var view = View0(); 

    // Create a submodel and pass it a function 
    // that will "subviewify" the submodel's view 
    var model1 = Model1(function (subview) { 
     view.subviewify(subview); 
    }); 

    // Return model methods that can be used by 
    // the controller (the onchange handlers) 
    return { 
     'updateModel1': function (newValue) { 
      model1.update(newValue); 
     } 
    }; 
} 

function Model1(makeSubView) { 
    var info = ''; 

    // Make an associated view and attach the view 
    // to the parent view using the passed function 
    var view = View1(); 
    makeSubView(view.__view); // Dirty dirty 

    // Return model methods that can be used by 
    // the parent model (and so the controller) 
    return { 
     'update': function (newValue) { 
      info = newValue; 

      // Notify the view of the new information 
      view.events.value(info); 
     } 
    }; 
} 

function View0() { 
    var thing = document.getElementById('theDiv'); 
    var input = document.getElementById('theInput'); 

    // This is the "controller", bear with me 
    input.onchange = function() { 
     // Ugly, uses a global to contact the model 
     main.updateModel1(this.value); 
    }; 

    return { 
     'events': {}, 

     // Adds a subview to this view. 
     'subviewify': function (subview) { 
      thing.appendChild(subview); 
     } 
    }; 
} 

// This is a subview. 
function View1() { 

    var element = document.createElement('div'); 
    return { 
     'events': { 
      // When the value changes this is 
      // called so the view can be updated 
      'value': function (newValue) { 
       element.innerHTML = newValue; 
      } 
     }, 

     // ..Expose the DOM representation of the subview 
     // so it can be attached to a parent view 
     '__view': element 
    }; 
} 

一个人如何在JavaScript中更清洁的方式实现MVC?我该如何改进这个系统?或者这是完全错误的路要走,我应该遵循另一种模式?

+0

(四年后)使用AngularJS。 – 2014-04-21 09:45:42

+1

如果您只是想了解MVC如何在Javascript中工作,那么询问如何实现它是非常合理的。太多的开发者现在都在使用框架,而没有真正理解他们的工作方式。 – NobodyReally 2014-08-07 15:38:42

说实话,MVC不太适合Javascript。它可以支持设计的基本原理,当然 - 您可以创建伪类作为控制器或模型,支持基本继承,并且可以让它操纵或创建任意数量的DOM元素,但是您付出的代价是 - 在开销,可访问性和可用性方面。

在我看来,我认为Javascript更多的是一种增强 - KISS的心态是存在的一个很好的理由。如果您对更好的方法来组织代码感兴趣,总是可以选择将相关功能打包成模块(原文如此),并根据需要抽取部分内容。例如,创建工厂以执行更复杂的AJAX请求管理,或者使用伪类来处理相似类型的数据。使用控制器的标准基本函数,模型等的另一个作为这些对象的新实例的原型可以实现类似的功能......但是,这又有点违背Javascript的五谷。

不过,如果你被困在MVC的想法只是为结构的缘故,可以考虑类似如下:

;(function(window, $) { 
    /** 
    * Event Object 
    * A quick description goes here. 
    **/ 
    var Events = window.Events = { 
     'bindTrackables': function() { 
      $('a.trackable').live('click', function() { 
       if(!_gaq) 
        _gaq = []; 
       _gaq.push(['_trackPageview', '/ajax/foobar']); 
      }); 
     }, 
     'bindSomeEvent': function() { 
      // etc 
     } 
    }; 

    /** 
    * Data Cache 
    * I'll need to remember stuff later, so I store it here 
    **/ 
    var Cache = window.Cache = { 
     'data': {}, 
     'store': function(key, value) { 
      Cache.data[key] = value; 
     }, 
     'fetch': function(key) { 
      return Cache.data[key]; 
     } 
    }; 

    /** 
    * Request Object 
    * Stores native AJAX requests for later use 
    **/ 
    var Request = window.Request = { 
     'current_requests': [], 
     'send': function(url, type, data, callback) { 
      Request.current_requests.push($.ajax({ 
       'url': url, 
       'type': type, 
       'data': data, 
       'callback': callback 
      })); 
     }, 
    } 

    // add some private logic here 
})(window, jQuery); 

这是非常基本的,但你的想法。模块化代码是关键......在JS中,这比强制应用程序(或语言)适合某种风格更重要。

+1

我完全同意你的观点,但我的应用程序很复杂(这是一个Gmail应用程序 - 几乎没有那么大,但关键还是在于)。即使组织与你的文章中的模型类似,代码也是一团糟。我必须找到一些组织模式,所以我没有发疯。如果实施(好)很麻烦,我不需要坚持MVC,但是在那种情况下,我确实需要替代模式。 – 2010-06-14 19:23:04

对于JavaScript JavaScriptMVCpureMVC,至少有一些已建立和可用的MVC框架。可能还有更多。我已经使用基于浏览器和Air应用程序的JavaScriptMVC并继续回到它 - 它有它的问题,但我发现它非常有用。
还有其他的解决方案,看看Sammy,这是我听到的好消息。我没有用过自己,但打算尽快尝试。我对它的描述不够充分,但对我来说,它似乎是一个在路线上工作的前端控制器,一个模板系统和ReSTful数据存储。我不确定它是否是MVC,但具有相似的成分。我不得不不同意mway's answer。 MVC在JavaScript中可能有点不同,但其好处对于organising this mess非常重要。通常与面向对象语言相关的设计模式不会因为js不是基于类而离开窗口。

我会说MVC比基于请求的(服务器端)应用程序更适合JavaScript应用程序。这些对象可以在一页JavaScript应用程序中停留一段时间 - 分钟(如果不是几个小时) - 并且组织良好的组织交互的方式将使您的代码更加健壮并易于处理。 There are books on the subject.

关于您发布的代码的其他几点。

  • 视图对象负责将事件侦听器应用于DOM元素。这是控制员的工作。该视图只呈现HTML - 控制器监听事件并相应地执行操作。
  • 您的模型似乎知道您的意见。模型层应该对视图层有最少的知识(可能注册为observers)。保持你的模型干净,关键点,我的意思是业务点 - 业务逻辑。在js应用程序中,您可能只是代理服务器端的模型层,但重要的是让您的模型保持业务逻辑,而不是其他任何东西。应用程序逻辑是控制器作业