资讯专栏INFORMATION COLUMN

使用 Backbone.Marionette 管理复杂 UI 交互

Loong_T / 3351人阅读

摘要:所以大量的问题都留给开发者自己想办法来解决,因此遭到吐槽当然,使用纯开发一个复杂应用时,情况就会变得非常糟糕。管理复杂的交互自己维护。影响了集合的排列。在中调用这样做是不对的,因为会让应用越来越复杂的。

只扯蛋,不给代码,就是耍流氓 -- honger。

完整的 tutorial 代码 戳这里, 因为我使用的是 commonjs 规范,基于 spm 的,你可以先安装,然后运行它。更多 spm 资料

// 安装
npm install spm -g

// 运行
spm server

这个 repo 是我学习各种技术栈的一个集合,如果是初学者,可以跟我一起来学习,也可以私信我。

你也可以 find me on GitHub

Backbone.Marionette 的中文资料真是少之又少,因此这篇会尽量介绍的较为详细。

很多人抱怨和吐槽 Backbone , 觉得它太简单了。什么事都要自己做。然而,Backbone 的优点也是它太简单了,它的思想就是不作任何绑定, 只提供一个骨架。正如 Backbone 的中文意思。

所以大量的问题都留给开发者自己想办法来解决,因此遭到吐槽...

当然,使用纯 Backbone 开发一个复杂应用时,情况就会变得非常糟糕。

纯 Backbone 的工作流程是这样的: MVP

                      events                               commands
Template/DOM (View) ----------> Backbone.View (Presenter) ----------> Backbone.Model (Model)
        |                           |         |                                 |
        |            updates        |         |             events              |
        |<--------------------------|         |<--------------------------------|

其中涉及的问题有:

业务逻辑: model 和 collection 处理大部分逻辑。他们对应着服务端后台的资源,也对应着视图显示的类容。

构建 DOM:一般是 handlebars。

视图逻辑:Backbone.View ,其中的逻辑要自己维护。

视图和模型同步: 自己维护。

管理复杂的 UI 交互:自己维护。

管理状态和路由:Backbone.Router(不支持管理视图和应用状态)

创建与连接组件: 手动实现。

管理复杂的 UI 交互

那么,这篇文章着重于讲 UI 交互,所有的 UI 交互都可以被划分为:

简单交互:使用观察者同步(Observer Synchronization),被动控制显示,操作 DOM 事件来改变集合模型,视图监听集合模型的变化来改变自身。Backbone.View 就是这样工作的。

复杂交互:使用流同步(Flow Synchronization),主动控制显示 SUPERVISING PRESENTERS

使用 Marionette 工作流程是这样的:

                         events for
                     complex interactions                                  notice
Template/DOM (View) ----------------------> Marionette.View (Presenter) ------------> Backbone.Model (Model)
        |                                           |        |                                |
        |               complex updates             |        |             events             |
        |<------------------------------------------|        |<-------------------------------|
                                                             |                                |
                                                             |        simple updates          |
                                                             |------------------------------->|
视图 View & 区域 Region

Marionette 扩展了非常丰富的视图 View 组件:ItemView CollectionView CompositeView LayoutView .

不仅于此,Marionette 还使用 Region (区域)来配合 View (视图)。

一般会先添加一个 Region 来定位一块地方,再决定这块地方显示哪个 View 。

// 你可以理解为一个中心 APP 对象。当一切准备就绪的时候,调用 App.start(options) 启动应用。
var MyApp = new Backbone.Marionette.Application();

// 添加一个 region,它对应一个 dom 节点
App.addRegions({
  mainRegion: "#content"
});

// 让这个 region 显示一个视图, 这个视图会立即渲染
App.mainRegion.show(new MyView());

从头说起吧,你可能注意到了,上面实例化了一个 Marionette.Application 对象。

通常需要定义一个 App ,通过 Initializers 把所有的事都绑定在上面。等待 start 方法调用的时候,开始执行。

// start 方法调用后,立即执行 Initializers
MyApp.addInitializer(function(options) {
  // 实例化 compositeView
  var angryCatsView = new AngryCatsView({
    collection: options.cats
  });
  // 显示这个视图
  MyApp.mainRegion.show(angryCatsView);
})

MyApp.start({cats: cats});

这里只绑定了一个 Initializer,在一个复杂的应用中,你可能会绑定多个的。start(options) 中的参数 options 会传递个每个 Initializer。

通过扩展 Backbone.Events, 实现 Aspect(切面编程) 你可以监听这些事件,让应用更加灵活。

之前分析过 Arale 的 Events 代码,现在的 Backbone.Events 就是从 Arale 的 Events 合并过来的,看我的 gitbook

App.on("initialize:before", function(options) {
     // doSomething...
});
App.on("initialize:after", function(options) {
     // doOtherthing...
});
App.on("start", function(options) {
  Backbone.history.start();
});

好了,现在已经知道了 Marionette 是怎么启动的了,下一步是了解它是怎么管理视图 View 的。

LayoutView

布局视图,比如你的界面上可能用 header main footer 等区域。

你可以这样来定义布局视图,这样你就掌控全局了。

var RootLayout = Backbone.Marionette.LayoutView.extend({

  el: "#content",

  regions: {
    header: "#header",
    main: "#main",
    footer: "#footer"
  }

})

一般会把这个 root 挂载到 App 上。

var MyApp = Backbone.Marionette.Application.extend({
  setRootLayout: function () {
    this.root = new RootLayout();
  }
});

// App 启动前,实例化它,得到 App.root
MyApp.on("before:start", function () {
  MyApp.setRootLayout();
});

现在 App 上有了 root 的控制权了,可以任意设置某个区域显示某个视图了。

MyApp.root.showChildView("header", new HeaderLayout());
ItemView 与 CompositeView

单条记录 Model 对应 ItemView, CompositeView 不仅对应的是一个包含 ItemView ,还对应有其他一些相关视图.

他们通常在一起使用,并且 ItemView 是 CompositeView 的 childView 属性值。

比如这样两个 template



  Name





{{name}}

我需要在 tbody 标签下加入多个 ItemView。这样你就需要使用 childViewContainer 来指定 childView 被加在什么地方。

很显然此处: {childViewContainer: "tbody"}.

这里是以上代码

var AngryCatView = Backbone.Marionette.ItemView.extend({
  template: require("./tpl/angrycat.handlebars"),
  tagName: "tr",
  className: "angry_cat"
});

var AngryCatsView = Backbone.Marionette.CompositeView.extend({

  tagName: "table",
  id: "angry_cats",
  className: "table-striped table-bordered",

  template: require("./tpl/angrycats.handlebars"),

  childView: AngryCatView,

  childViewContainer: "tbody"

})

细心的童鞋应该已经注意到了,模板中为什么不用 table 标签包裹起来。这是因为 Marionette 会为你包裹一层,若你不指定 tagName 则默认是 div 标签。 指定的 className, id 属性也是加在这层上面的。

纯 Backbone 代码需要自己来实现 render 渲染 DOM,在这里 Marionette 通过指定的 template 属性自动渲染了。

重点 在 这一层 我们要做的是监听 Model,Collection 的变化,来同步视图。和 Backbone 做法一样。不同的是,Marionette 可以指定是全部重绘(render)还是部分重绘(renderCollection)

Event Aggregator

事件聚合器,这个东西主要是用来解耦的,例如:从 ItemView 上来个事件,改变了 model 的属性。影响了集合的排列。需要更新到 CompositeView 上。

在 ItemView 中调用 CompositeView ? 这样做是不对的,因为会让应用越来越复杂的。视图 View 也不应该去处理 business logic。

使用 Event Aggregator 会让程序解耦,它相当于一种 Publish/Subscribe 模式。视图只需要去通知 notice 模型 Model or Collection 来处理。

MyApp.trigger("rank:up", this.model);

在模型 Model or Collection 初始化的时候就要 Subscribe 订阅事件 rank:up

MyApp.on("rank:up", function(cat) {
  if (cat.get("rank") === 1) {
    return true;
  }
  self.rankUp(cat);
  self.sort();
})

这样的话,business logic 就是在 Model or Collection 中维护的。

以上总结

Marionette.View 在 Backbone.View 之上多做了很多事情,包括自动渲染和重绘等等。

Marionette.View 接到 Dom 事件后,可以通知 notice 集合 Collection 去处理。也可以直接命令 commands 模型 Model 去处理。

(这里只介绍了一些入门知识 Marionette 未完待续...)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78206.html

相关文章

  • 2017-07-04 前端日报

    摘要:前端日报精选一起探索的众成翻译性能优化杀手掘金入门知乎专栏用实现无限循环的无缝滚动蚊子的博客前端每周清单组件解耦之道基于的自动化测试是否为时已晚中文译如何在无损的情况下让图片变的更小掘金第期用上古思想写现代前端踩坑集锦掘金 2017-07-04 前端日报 精选 一起探索 ES6 的 Generators - 众成翻译V8 性能优化杀手 - 掘金入门TypeScript React - ...

    kelvinlee 评论0 收藏0
  • 实现一个稍微复杂的simplelist

    摘要:是一个专门为应用所设计的集中式状态管理架构。此时可以帮助我们实现状态的管理。每个任务都归属于一个清单,有唯一的清单。说到这,一个复杂的的基本结构和功能已经出现了。 使用过一些清单类的应用程序,像 WunderList, Google Keep等,用来记录一些计划和安排,也试着将自己的计划安排同笔记一起整理在 Evernote 中,但是无论哪种方式用起来总觉得少了点什么,如果两者的一些功...

    solocoder 评论0 收藏0
  • 简析React 和 Redux 的特点和关系

    摘要:这对复杂问题定位是有好处的。同时,也是纯函数,与的是纯函数呼应。强约束约定,增加了内聚合性。通过约定和全局的理解,可以减少的一些缺点。约定大于配置也是框架的主要发展方向。 React+Redux非常精炼,良好运用将发挥出极强劲的生产力。但最大的挑战来自于函数式编程(FP)范式。在工程化过程中,架构(顶层)设计将是一个巨大的挑战。要不然做出来的东西可能是一团乱麻。说到底,传统框架与rea...

    iOS122 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<