在介绍Nervenet起源时我提到,Nervenet一名很大程度上来自于Backbone。使用Backbone进行开发期间,我体会到很多方便之处,也发现仍有不少障碍横垣在前,于是总结之前的经验,取Robotlegs之长,做出了这个框架。当然,Nervenet并非专门针对Backbone开发,自然也不会依赖它,不过由于设计初衷和后期实现,结合Nervenet使用Backbone时着实有一些优势。
用context.createInstance
创建实例
我们知道,依赖注入的对象一般都是类的实例;类实例化时,可能会用到一些尚未注入的属性,所以通常需要在注入后调用实例的postConstruct
方法,才能彻底完成构造。Backbone为了实现其独特的架构,将真正的构造函数construct
隐藏了起来,开发者操作的initialize
函数实际上是初始化函数,从执行顺序来讲与上文中的postConstruct
基本一致。同时,Backbone的几大基础类都接受传入初始化对象,即new Backbone.View(options);
中的options
,options
中若包含el
、model
等属性,将直接用来填充类自身的属性,甚至从页面当中找到dom结构操作。
若采用普通的依赖注入,则需要在每个类中再实现一个postConstruct
方法,增加维护成本和迁移成本。使用Nervenet提供的context.createInstance方法,可以在实例化对象时,扫描参数对象,完成注入,只需要保留initialize函数
,非常简单,而且可以直接沿用之前的代码。
var view = context.createIntance(Backbone.View, { model: '{{$model}}' });
从代码可以看出,要完成上述功能,还必须实现一个特性:“注入指定类型的对象”。Javascript是弱类型语言,代码中不包含对象类型,所以之前的类库只能根据“属性名”注入。对于Backbone来说,model
、collection
这些都是特有的关键字,要注入的也多是它们,而要注入model
,就必须先map
一个值到model
这个key
中——这意味着同一组map
只能给单一Backbone.View
对象注入依赖,在实际开发难以想象。Nervenet的优势在于可以由“属性值”指定注入的内容,这样不同的View
,可以指定不同的model
,问题迎刃而解。
// 给不同的view注入不同的model context.createInstance(Backbone.View, { model: '{{$user-model}}' }); context.createInstance(Backbone.View, { model: '{{$job-model}}' });
(infuse.js的解决方案是“子注入器”,通过创建子注入器,构造不同的map
,就可以对不同对象注入不同的值了)
用mediatorMap
管理mediator
了解Backbone的人都知道,虽然名为View
,但其实Backbone.View
更接近一般意义上的Mediator
,而通常意义上的View
则由HTML+CSS负责实现。我通常使用Backbone.View
开发组件,组件拼接起来就是完整功能的页面嘛。所以我就设计了一个功能来帮助我管理mediator
,就是context.mediatorMap
,它主要提供三个方法:
.map(selector, MediatorClass[, options])
,通常和.check(dom)
连用。前者将选择器和类关联,后者则检查某个DOM节点下是否有符合选择器的节点,并为它们自动创建mediator
。
// 先这么注册一下 context.mediatorMap.map('.checkbox', MyCheckbox, options); // 然后就可以用了 context.mediatorMap.check(document.getElementById('my-form'));
.createMediator(dom, MediatorClass[, args])
,直接为某DOM节点创建mediator
。
// 直接为DOM创建mediator context.mediatorMap.createMediator(document.body, MyGUI);
创建mediator
的过程基本相同,自动注入依赖,并把目标DOM节点会作为第一个参数,或者第一个参数对象的el
属性传给mediator
的构造函数——后者当然是为了兼容Backbone。
Backbone基于jQuery,所以操作一个DOM和操作一组DOM对它来说没有什么区别,留意到这点后,我在Nervenet中也作相应照顾,可以通过options
设置isSingle=true
;表示使用者希望使用一个实例来管理所有符合要求的节点。默认false,会针对每个DOM节点创建独立的mediator
。
可惜的是,HTML没有提供方便的手段获取DOM节点的变化,所以暂时只好使用手工检查了;另外,querySelectorAll
这个方法也存在一定的兼容性问题,所以,目前mediatorMap仍然只是0.1.2版的测试功能,以后可能会有各种改动。
欢迎吐槽,共同进步