JavaScript 中的代码组织:MVC?自渲染组件?

Posted

技术标签:

【中文标题】JavaScript 中的代码组织:MVC?自渲染组件?【英文标题】:Code organization in JavaScript: MVC? Self-rendering components? 【发布时间】:2011-07-17 23:58:28 【问题描述】:

我正在构建一个非常依赖 JS 的 Web 应用程序。我说这是 JS-heavy,因为绝大多数工作都是在客户端完成的(尽管有一些使用 AJAX 和 XMPP 来回同步到服务器)。

这是我第一次在纯 JS 中(使用 jQuery)构建这种规模的东西,所以我开始使用 MVC 以模仿 Rails 的方式组织我的代码。例如,如果用户单击一个按钮,则会在 Controller 对象中调用一个方法,该方法从模型中提取一些数据,然后将数据传递给视图函数。我几乎对所有事情都这样做,甚至是像显示一个小弹出窗口这样的琐碎操作。

几个月后,我觉得我没有充分利用这门语言。我真的应该像网页一样呈现我的视图吗?

将视图分解为组件似乎更有意义,这些组件将是 javascript 对象/函数的实例。例如,而不是...

var itemListhtml = '<ul id="item-list"><li>item1</li><li>item2</li></ul>';
jQuery('#container').html(itemListHTML);

...我本来可以...

components.itemList.render();

所以这里只有一个名为itemList 的组件。由于所有数据都存储在客户端上,因此这些组件可以立即访问创建和管理自身所需的所有数据。我想我仍然会使用 MVC,但不需要负责整个视图的控制器操作。如果我想刷新 UI 的一部分,我只需调用 whateverComponentControlsThatArea.redraw() 并重新呈现自己。

我确信以前有人这样做过。这种代码组织方式有名称吗?有关如何实施它的任何指南或最佳实践?

【问题讨论】:

你见过backbone.js吗? documentcloud.github.com/backbone 现在正在阅读,目前看起来很棒 很难说出你真正的问题是什么 【参考方案1】:

现在有许多可用的 javascript MVC 框架例如JavaScriptMVC、PureMVC、Sammy.js。 通常通过某种模板引擎处理视图或子视图的呈现。 JavaScriptMVC 有一个模块EJS,它以ERB 为模型,我发现它非常有用。模板可以编译成函数以加快生产速度。 还有其他模板解决方案,例如 John Resig's Micro-Templating 和 many more

如果还不算太晚,我建议您使用其中一种框架。我已经在几个项目中使用了 JavaScriptMVC,并且可以推荐它(文档需要一些时间来适应)

【讨论】:

【参考方案2】:

您真的应该研究 jquery.tmpl (http://api.jquery.com/jquery.tmpl/) 以创建适合构建视图渲染的快速 javascript 模板。

【讨论】:

【参考方案3】:

聚会有点晚了,但我这里有 0.02 美元,我不知道该怎么处理...

暂时忘记(典型的)Web-MVC(即:RailsMVC 等):

考虑到 JavaScript 可以都驻留在同一个地方,并且您不必担心确定路由和类实例化(除非您真的想这样做)。

理想情况下,从软件的角度来看,您希望 MVC 做的是将用户所做的事情与构成内容的内容(基于动作)和构成视图的内容(基于动作)分开)。

没有什么说你不能有多个视图,甚至你不能有一个包含多个视图的视图(可能使用模板,或者是功能生成的,并附加到一个 DOM 节点 - 要么是有效)。

在一个简单的伪示例中,而不是具有如下所示的流程:

动作加载控制器 -> 控制器加载模型 -> 控制器查询模型 -> 模型回答控制器 -> 控制器加载视图 -> 控制器将数据馈送到视图 -> 视图将页面发送到控制器 -> 控制器输出页面

为什么不这样:

Controller 监听 Action (addEventListener) -> Controller 将 Action 变成 State-Logic -> Controller 通知 Model (observer) OR Model Polls Controller -> Model 根据逻辑改变状态,并收集/排序所有数据 -> Model Notifies View (observer) OR View Polls Model -> View Changes State based on Logic -> View Renders all Components, based on Data + ViewState (innerHTML OR documentFragment)。

它看起来有点长,但实际上,一切都很好而且分开。 使用视图(或视图管理器,或者你想怎么想)来规定页面上的窗口、每个窗口的组成方式、数据的去向、每篇文章的内部、每个窗口中...

...现在你有一个 MVC 模式,但你也有能力说:

View["mainpage"] = 

    data :  tweets : [id:......]/* et cetera - pushed by Model, not Controller */ ,
    layout : [ "Header", "Carousel", "Articles", "TwitterFeed", "RSSFeed", "Footer" ],

    // if your system is this clean, you could even prototype the content-builders
    // rather than defining them in each ViewState - you'd just need layout, then
    buildPage : function () 
        var page = document.createDocumentFragment();
        for (/* everything in this.layout */) 
            View.build[this.layout[i]](this.data, page);
        
        document.body.appendChild(page);
    ,

    cleanUp : function ()  /* fancy or simple DOM cleaning for state-change */ ,

    // grabs SubView by expected handle (id="tweetfeed" or whatever) and replaces it
    // observer functionality, for views to automatically update as data changes
    updateView : function (view, newData)  ... ,

    addData : function (data)  this.data = data; , // for Observer

    /* Observer - if you want to run the WHOLE site with AJAX from index.html
     * clean up old (ex:"main") page and build and/or transition new (ex:"media") page
     * could be unique for each page, for custom transitions, or just prototype it */
    changeState : function (newState, newData) 
        View["mainpage"].cleanUp();
        View[newState].addData( newData );
        View[newState].buildPage();
    

现在您已经定义了整个主页。 当然,不仅要维护主页的定义,还要维护每个页面/部分的定义,这将是一项额外的工作。 ...然后,您需要创建将创建每个子视图的功能——但基于组件的设计正是您所要求的。 本质上,对于每个小部件,它都有自己的构建逻辑。 这就是视图的作用——它们要么有一个可以重复使用的单独模板,要么有一个每次都以相同方式工作的函数。

原子视图是您处理构建 1 个项目(1 个推文、1 个帖子、1 个商店项目)并为此构建视图的函数。 让 Single_Tweet 视图连续 20 次向页面发布一条推文对于 JS 性能来说是一个的想法。

但是,让 Single_Tweet 视图将推文按顺序推送到 Twitter_Feed 视图放在网站上的 Tweets 数组中是正常的。

如果你的页面是视图,由视图的小部件组成,由视图的原子单元组成,那就更好了。 当所有这些都发生在 DOM 之外(所以是 innerHTML 或 documentFragment)。

最好的框架是您以这种方式定义页面的框架,但您也可以随时根据模型的数据推送更新单个小部件。

这就是 AJAX 的美妙之处——老式的 MVC 可以发生,没有一个无所不知的控制器。

控制器只保存一个按键列表、鼠标坐标、点击按钮的意图...... 它告诉模型发生了什么事。 模型会处理所有与状态/数据/数据操作(排序)相关的事情,并将新状态或数据提供给视图,视图会按照您指定的顺序将其全部接收并放入 HTML。

就是这样。

【讨论】:

以上是关于JavaScript 中的代码组织:MVC?自渲染组件?的主要内容,如果未能解决你的问题,请参考以下文章

渲染阻塞 Javascript & CSS MVC4

[JavaScript]MVC浅析

JavaScript Extjs:根据其他字段的条件,使用自定义类渲染网格中的单元格

未呈现 MVC 4 中的自定义包

从控制器动态渲染动作 - MVC

Javascript MVC 学习笔记 视图和模板