Backbone.Marionette V组件制作的核心任务之一——将业务数据连接上交互界面

p.s. 原文标题:交互功能单元制作的核心任务之一——将业务数据连接上交互界面

开发JS APP的任务可归纳为主要的三项:制作V,用V组建PAGE,用PAGE组建APP。其中「制作V」作为交互功能的独立单元,是最基本,也是最核心的任务之一。「制作V」的一项关键任务,就是将业务数据M“连接”上V。任何V都是要 render 的,因为这是它的形式核心——计算对象的输出,但有一大部分的V则需要「先」绑定业务数据,binding 数据,是前render任务。

Scale up

本文略译自《Marionette Explained: Connecting Data to Your Views》,介绍Marionette将M“连接”上V的方式。

Marionette Explained: Connecting Data to Your Views

理论上,「交互功能」需界面(View)和数据(Model),Backbone设计了View类,也为View类设计了Model 和 Collection的属性,但是View的 Render方法是空的,没有将M的数据“连接”上V——渲染到DOM上。

Backbone考虑了灵活性而如此设计,然而这个设计,与 Ember, Angular and KnockoutJS等框架提供自动渲染,甚至是双向数据绑定(2 way bindings)的功能相比,显得很原始;打个比喻,Backbone的View,是个不能直接用的工具,像一把刀没有刀刃,还得自己磨。

所以选用 Backbone 开发JS APP项目,第一件事,是自己磨刀——决定View 绑定M的方式。

当然Marionette是个较完整的工具,帮我们磨好刀——提供了一种“结构化”的数据绑定方式(抽象去掉了重复的代码),同时还保持了自定义的灵活性。

Marionette.View类的内部数据处理过程

renderpattern 3

Marionette(的View类)内部渲染的过程(自动,但也可调整),类似于其它MVVM类框架,例如KnockoutJS 或 Durandal,主要分为两步(看上图)。

1.serializeData

第一步是 serializeData,将M转换为易渲染的数据格式;serializeData函数输出,相当于MVVM架构中的ViewModel。

串行化是什么?https://en.wikipedia.org/wiki/Serialization

In computer science, in the context of data storage, serialization is the process of translating data structures or object state into a format that can be stored or transmitted and reconstructed later. When the resulting series of bits is reread according to the serialization format, it can be used to create a semantically identical clone of the original object.

这里“串行化”的任务是将你的业务数据对象(a Backbone Model or Collection)简化成View渲染时容易使用的格式。例如,Marionette默认将调用Model or Collection’s toJSON方法,将M转为一个简单的 JavaScript object。如果你的渲染任务有特殊需求,你可以重写(override) serializeData。例如,以下是Marionette TodoMVC 项目的一个片断,渲染一集todo项,其中的一部分是已经完成的,需另外计算并显示结果出来:

serializeData: function () {
    var active = this.collection.getActive().length;
    var total = this.collection.length;

    return {
        activeCount: active,
        totalCount: total,
        completedCount: total - active
    };
},

2.render

准备好了待渲染M的数据后,数据将被传给render函数,render先查找 UI template。

在Marionette里,View的UI template由「template属性」指定,如果你有多个情况需要条件判断(例如根据M的某个字段值选用不同的UI template),你可用「getTemplate函数」。

确定UI template后,render正式工作——使用template engine进行编译。Marionette默认使用Underscore提供的template engine,但是你也可以替换它。以下是我在某个Marionette项目,替换使用Handlebar的代码:

//render templates with Handlebars instead of Underscore
Backbone.Marionette.Renderer.render = function(template, data){
    var renderer = Handlebars.compile(template);
    return renderer(data);
};

#ItemView and CollectionView

CollectionView在新版api保留下来,它是一个异类,因为它管理子view的任务或责任,已经超出单纯的view(计算逻辑),但是它又不像region那样是一个通用的view mgr

所谓“交互功能”,是抽象一般的,具体V需要做甚,则是多样的,虽然像 itemView 那样展示m的状态是常见

itemView的“交互功能”,就是展示/处理 某个业务数据对象 CollectoinView的“交互功能”,则是展示/处理 多个业务数据对象

views for a simple todo list might look something like this :

var TodoView= Marionette.ItemView.extend({
    tagName: 'li',
    template: '<span class="checkbox" {{checked}}></span><span class="text">{{ text}}</span><span class="delete"></span>',
    events: {
        'click .checkbox': 'toggleChecked',
        'click .delete' : 'deleteItem'
    },

    serializeData: function() {
        return {
            checked: this.model.get('checked') ? 'checked':'',
            text: this.model.get('text')
        };
    },
    
    toggleChecked: function() {
        //logic for checking the box
    },
    
    deleteItem : function () {
        //logic for deleting the todo
    }
});

var TodoListView = Marionette.CollectionView.extend({
    childView: TodoView,
    tagName: 'ul'

});

关于 2 way data-binding

Marionette的数据绑定是单向的,关于「MV数据绑定」的形式,在过去几年里,社区意见有过“反复”和争论。在 Backbone刚出来的时候,大家认为“MVC结构式很COOL”,然后MVVM类框架出现后,大家又认为“双向绑定才是王者”,再到近来的React的火热,大家又说“单向绑定能保持简洁”。

在这篇文章中,我不打算深入讨论这个争论,因为到目前还定论;然而Marionette的重要的特征是,Marionette通常更喜欢显式绑定而不是隐式绑定。因此,当模型值发生变化时,它将基于你编写的代码,而不是隐式的库代码。

小结

在这篇短文里,我只介绍 Marionette 中,制作单个V(交互功能)中的核心任务[注]——绑定M到V,由于Marionette 的结构化绑定方式简洁明了,这是Marionette的获得成功的原因。

注:制作V(交互功能)的其它任务包括,交互事件的处理

如果你使用这些约定的一致的绑定方式制作V,你可以从一个view切换到另一个view,或从一个项目切换到另一个项目,并快速了解代码的意图和结构。你可以依赖其他人的经验,并专注于编写代码来实现应用程序的目标,而不是试图为每个view解决这些问题。

这是深入研究Marionette的一个短暂但重要的开始。在后续的系列文章中,我将讨论layouts、view的生命周期和其他Marionette特性,但是web应用程序的核心是「用丰富的UI来展现业务数据」。没有这个核心,你的web应用程序就根本没有什么功能。

参考

https://marionettejs.com/docs/master/view.rendering.html

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