使用Marionette.js构建复杂的交互布局

本文略译自《Building Complex Layouts With Marionette.js》,主要介绍——交互页面的布局需求。

当我们开发一支较复杂的web交互应用程序,首先摆在设计师的第一个问题(之一)是,如何规划交互页面的内容结构和位置布局(structure and layout of your application)。大多数交互应用程序有这样的布局结构:

  • 第一,页面有一些是静态的区域,例如导航栏(navigations)和页面脚部(footers);
  • 第二,页面有一些是动态的区域,例如主内容区,或页面相关的交互控件;

静态区域则比较容易,动态区域则需要某种管理功能,能内容调入调出(swapping out)。在Backbone里,怎么实现布局呢?尤其是有动态区域的布局结构?

用Backbone.View手动创建布局

Backbone.View本身是管理页面内容[注]的,布局也是页面内容之一,所以完全可以用View手动创建布局;然而Backbone.View功能比较精简,和原始,没有任何创建复杂布局的指导(尤其缺乏动态替换局部内容的功能),例如复杂布局需要解决几个问题:

  1. 我可用以一个View来做一个页面,页面内容布局由HTML template和jQuery实现吗?
  2. 还是,我需要为每一个区域做一个View,再把综合起来?
  3. 又或者,我为页面做一个顶层的View,它负责管理布局中不区域的子View?

以上三个使用Backbone.View做布局方案都是可能的,没有谁强调一定要使用哪一种。

注:View对象实例的构建

因为Backbone官方保留了一切的自由,没有明文规定的处理子View,和View的构建的方式。

View对象实例的构建分为,第一渲染UI(将 template等转换成挂接DOM容易的形式),第二,将渲染的结构挂接上DOM,两步。

Marionette.Regions

作为最流行的Backbone拓展应用框架,Marionette给出近乎完善的方案。在系列的第一篇文章里,我提到应用框架(像Marionette)就是帮助架构师做设计的决定的,「页面布局的实现方式」就是另外一种非常重要的设计决策。Marionette提供 Regions对象做为制作布局的重要技术基础——管理子V的功能。

Marionette.Region技术及其Layout应用

~

Regions的技术本质

Marionette很早就提出Region对象,使用Regions对象,View能内嵌子View,能动态替换子View,实现复杂V的制作。

应该说,Region的通用本质,是制作复杂的V——有嵌套子V的交互功能;制作页面布局则是「Regions技术的一种应用」,

Regions增加View生命长度

有了Regions对象将子V的置入,Views的生命步骤多的 Regions 一步,故Regions能触发生命事件——在region的内容变化前后的生命事件(onShow/onBeforeShow)。

Regions自动管理子view生命

由Backbone.View的功能过于原始,用它来制作「嵌套View」是很麻烦的,代码多,而且一不小心就会产生内存泄漏。Marionette.Regions 的管理功能自动处理了子V的创建,替换和回收,消除内存泄漏的风险之外,还隐藏很boilerplate code。

LayoutView 和 Layouted View

Region与View Manager

Regions对象是管理View(生命)相关的,所以不能独立使用,它只能结合一个「管理View的对象」——View Manager使用。「管理View的对象」例如包含子View的父View,例如顶层的页面对象和程序对象(后二者可看作一个特殊的View)。

将View基类变成一个Layouted View

Marionette早期版本设计了 LayoutView,在View类的基础上结合 Region对象,专门用来制作页面布局,和多层嵌套UI;后来作者为简化API将Region对象 直接集成进View基类,省掉了LayoutView,将View基类变成一个Layouted View。

将View基类变成能嵌套的View

Marionette APP可以用一个顶层View来制作主页面,在这个root View里可包含多个Regions来划分不同的页面区域,每个区域“安装”不同子View。由于View是一个Layouted View,具有布局功能,所以每个区域的子Veiw也可以进一步划分不同子区域,如此往下的不限嵌套深度。

模块化交互功能

利用Region技术如此划分页面布局,表现了一种重要工程思想,就是模块化。整个页面甚至应用程序的交互功能,被逻辑划分一个个可独立制作,动态替换,和相互协作的交互功能组件。

以上是Region技术原理,和划分交互功能的理论,接下来介绍Region的API。

Region的API

Region的API主要分为两大类:第一类是在某View管理对象(例如父V或app对象)上创建region对实例;第二类是利用某region对象实例管理子view。API大略如下,详细请查看文档

  • region创建
    • 声明式创建 region对象
    • 扩展region 类
    • 动态添加region
  • region的使用
    • 显示/隐藏View
    • 卸载View
    • ……

这里简要介绍下region创建,并举一个实例。

region hash

使用 region 无需单独创建它,你可以像创建事件对象,使用一种类似 event hash 的声明方式创建「View 的 region」,region hash的一项创建一个region对象。最简单region,只有单键值对象,键名是region名,值是一个jQuery selector ,例如:

import { View } from 'backbone.marionette';

const MyView = View.extend({
  regions: {
    mainRegion: '#main'
  }
});

如果你有更复杂的创建需求,你可以使用regions function ,只要包括一个键值对的对象即可。例如:

 ```js import { View } from 'backbone.marionette';

const MyView = View.extend({ regions(){ return { firstRegion: '#first-region' }; } });

### 使用 region 创建页面布局

以下是一个简单的使用 region创建了三个区域的简单布局的例子:
```js
var Mn = require('backbone.marionette');
var Radio = require('backbone.radio');
var FooterView = require('views/footer');
var HeaderView = require('views/header');
var IndexView = require('views/index');

var RootView = Mn.LayoutView.extend({

  regions: {
    header: '#navbar',
    content: '.content-area',
    footer: 'footer'
  },

  initialize: function() {
    Radio.channel('root').comply('set:content',function(contentView) {
        this.getRegion('content').show(contentView);
    });
  },

  onBeforeShow: function() {
    this.getRegion('header').show(new HeaderView());
    this.getRegion('footer').show(new FooterView());
    this.getRegion('content').show(new IndexView());
  }

});

这个例子中,RootView 可用作一个顶层的View,它定义了三个regions:header 和 footer 是静态的内容,content area 初始为index View的动态区域。在RootView的 initialize函数里我们安装了Backbone.Radio 的命令监听函数,负责监听外部的命令消息(例如来自router)动态置换content area 的内容 View。

marionette regions 1 例子中,我们也安装了View的BeforeShow 的生命事件勾子onBeforeShow (对象生命事件勾子将在另一篇文章中介绍)。这个勾子函数会在View(RootView)所在region show它之前执行(RootView本身也可以做为另一个View mgr的子View)。勾子函数的任务是show 子view;这里的逻辑是,嵌套的View里,最内层的子View先show,这样可以保证你的View只挂接DOM一次,从而避免了浏览器重绘页面多次。

海龟之下还是海龟

EM:注意以下内容的LayoutViews和ItemViews在最新版里已经被抽取进通用View类里,它们分别代表新View不属性API。

Marionette为我们设计的「View对象系统」可称完满了,你可这个系统里的的三种View(ItemView, CollectionView, and LayoutView)开发大部分的交互界面,包括列表,和复杂的布局。使用它们的基本规则是:

  • 第一,LayoutViews 用来逻辑划分功能较多的page,和复杂的交互功能,例如有嵌套子View的;
  • 第二,ItemViews 用来抽象「单一业务对象」的交互功能;
  • 第三,CollectionViews用来抽象一集线性集合,每个集合都是相同的,但具有独立交互功能的;

以上的规则算是Marionette框架的应用“模式语言”(甚至是一切前端项目,只要理论化),有了这种“语言”,开发者之间的交流,和开展新的项目,都会变得很高效。

参考

https://spin.atomicobject.com/2014/01/25/render-nested-views-backbonejs/

裸男
Nakeman.cn 2023 Build by Gatsby and Tailwind, Deploy on Netlify.