如何构建大型应用程序

use*_*456 4 famo.us

我想知道如何构建我的应用程序.我应该使用自定义视图和一个将控制它们的主视图.或者将视图保存在灯箱中更好.我发现的所有示例都以某种方式限制了功能并呈现了一个或几个屏幕.组织更大的应用程序的正确方法是什么?

mar*_*sen 5

我也在想.

初始点:

  • Famo.us应用程序在分层渲染树中构建.
  • Famo.us使用RequireJS模块.
  • Famo.us鼓励使用Views
    • 视图是可重用的组件.
    • 视图封装了功能(以及渲染树的一部分).
    • 意见沟通使用的事件.
    • 视图由选项对象初始化.

我们需要添加管理结构:

  • 商业逻辑
  • 非API功能,如REST api调用,音频,本地存储等.
  • 数据流:
    • 更新用户输入数据
    • 更新数据更改视图

模块,事件和松耦合

目标:

  • 可扩展的应用程序
  • 小型,独立,可测试的模块.
  • 促进代码的重用.
  • 轻松共享模块(只需删除项目文件)
  • 不依赖于其他Javascript框架.

通常,模块之间存在紧密耦合:

  • 模块实例化并保持对另一个模块的引用
  • 模块跨越它们的语义边界
    • 了解特定REST API的视图
    • 使用特定模型代码(如Backbone)的视图(请参阅Taasky示例)

以下是如何避免这种情况:

  1. 模块在发生有趣事件时发出事件(用户输入,数据更改等)
  2. 一个调解人侦听事件
  3. Mediator调用另一个模块的公共API.

因此,它不会让View模块知道Backbone模型的东西,而是发出如下的用户输入事件:

  1. Todo-Edit-View发出"用户输入"事件: "todo-update",{id:1,title:'Code'}
  2. Todo-Mediator听取了这个事件.
  3. Todo-Mediator调用tasks.find({id:1}).update({title:'Code'})Todo模块(例如使用Backbone)

规则

  • 有模块和调解器
  • 模块具有公共API并发出事件
  • API和事件保持其语义边界; 即"updateTitle()"而不是"onBackboneModelChange()"
  • Mediator将应用程序耦合,即骨干模型更改为待办事项标题更新.
  • 调解员是单身人士
  • 应用程序可以有多个调解器.

例如,像GMail这样的电子邮件应用程序可能会有调解器

  • 聊天功能
  • 待办事项列表功能
  • 阅读电子邮件
  • 编写和发送电子邮件

文件结构:

/src
   /lib
   /services
   /mediators
   /layout
   /content
   /config
   /main.js
Run Code Online (Sandbox Code Playgroud)

模块类型:

  • 服务:一个独立的模块,用于封装非UI功能,例如:LocalStorage,Ajax,Web Audio等.
  • 布局:内容的布局,动画和定位,例如:ScrollView,HeaderFooterView等
  • 内容:应用的实际内容:渲染树的叶节点(曲面).

请注意布局内容之间的区别.通过从实际内容中分离UI组件和布局,可以轻松地重用UI模式,例如侧面板,弹出窗口,导航栏,粘贴标题,滚动视图等.

此外,我建议*.css为每个仅包含结构和最小主题的布局创建一个.所有主题都可以覆盖/扩展,因此很容易重新设置应用程序.config/theme.css

其他代码:

  • Mediator:使用事件和公共API耦合模块.
  • 配置:包含初始化时整个应用程序中使用的所有选项.
  • main.js:引导应用程序.

Main.js中的Bootstrap应用程序

  1. 创建调解员
  2. 创建服务
  3. 构造渲染树

模块生命周期

  • 模块必须包含在单个文件中,即依赖于外部库!

创建模块时,它会向所有调解员宣布其存在.我们使用Famo.us Engine发出全局事件.这将是唯一必需的依赖!

 Engine.trigger('created',this)
Run Code Online (Sandbox Code Playgroud)

当模块被销毁时,它会向所有调解员宣布它的销毁.

 Engine.trigger('destroyed',this)
Run Code Online (Sandbox Code Playgroud)

介体监听createddestroyed事件并将模块粘合在一起:

 var someDataModule; // Backbone or whatever
 Engine.on('create',function(module){
    if(module instance of SomeDataModule) {
        var someDataModule = module;
    }
    if(module instanceof TodoView) {
      module.on('change-title',function({id:id,title:title}){
          someDataModule.find({id:id}).set('title',title);
      })
    }
 }) 
Run Code Online (Sandbox Code Playgroud)

在简单的调解器中,您可以按顺序(即SomeDataModule之前TodoView)初始化模块.但是,在更复杂的情况下,您可能需要使用a Promise来结合所有内容.

关于依赖关系的注释

"自包含"模块有三个例外:

  1. 允许布局内容模块具有层次依赖性.父母可以初始化孩子,并期待这些孩子的某些事件.一个ListView可能初始化ItemView和处理ItemRemoved事件.

  2. 服务可以是Facade/Adapter,用于其他服务.例如,a DataService可能为a 提供简化,抽象和安全层RestApiService.

  3. 当然,调解员有硬连线依赖,因为他们结合了应用程序!