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

时间:2010-06-14 07:08:38

标签: javascript model-view-controller

tl; dr:如何以干净的方式在JavaScript中实现MVC?

我正在尝试在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?我该如何改进这个系统?或者这是完全错误的方式,我应该遵循另一种模式吗?

2 个答案:

答案 0 :(得分:6)

JavaScript JavaScriptMVCpureMVC至少有一些已建立且可用的MVC框架。可能还有更多。我已经将JavaScriptMVC用于基于浏览器和Air应用并继续回归它 - 它有它的问题,但我发现它非常有用。
还有其他解决方案,请看Sammy,这是我听到的一件好事。我没有用过自己,但打算尽快尝试。我不太了解它是否正确描述它,但对我来说,它似乎是一个前端控制器,它适用于路由,模板系统和ReSTful数据存储。我不确定它是否是MVC但具有相似的成分。

我不同意mway's answer。在JavaScript中实现MVC可能有点不同,但它的好处对于organising this mess非常重要。通常与OO语言相关的设计模式不会仅仅因为js不是基于类的。

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

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

  • 视图对象负责将事件侦听器应用于DOM元素。这是控制器的工作。该视图只呈现HTML - 控制器侦听事件并相应地执行操作。
  • 您的模特似乎知道您的观点。模型层应该对视图层知之甚少(可能注册为observers)。保持模型清洁,重点,我的意思是业务点 - 业务逻辑。在js应用程序中,您可能只是代理服务器端模型层,但重要的是让您的理智将模型保持在业务逻辑中而不是其他任何内容。应用程序逻辑是控制器作业

答案 1 :(得分:0)

老实说,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中,这比强制您的应用程序(或语言)适合某种风格更重要。