Tangram的插件设计

一个基础库一般是由两大部分组成,一部分是其核心的基本方法,这些方法是这个基础库的根本;而另一部分则是开发者或者用户对于库的扩充,一般情况下,这种扩充也就库的插件。Tangram也不例外,需要插件来使其羽翼更加的丰满,给用户带来更多更好的功能体验。那么如何设计插件,如何让插件的用户体验更好,就是我们接下来面对的首要问题。为此JS小组的同学们在实践的过程中,不断讨论设计,最后发布了tangram的首批插件,draggable(拖拽)、selectable(选择列表)和sortable(排序列表)。那么tangram插件究竟是如何设计的呢?

一、面向用户的设计思路

如何来设计一个通用方法,是很多开发者要面对的问题,也是设计库或者组件的基础,这决定了一个库设计的核心思路。曾经在 tangram1.x 时我们犯过一个错,我们真的像程序员一样让每个方法都特别整洁,甚至在这个方法中对于参数都没有做校验。基于这样设计,我们真的使每个方法都是不耦合的,每个方法都是性能最高的。但是在真正的使用过程中却发现用户想要的并不是这样的一个库,原因很简单——它不够简单、好用。

实践是检验真理的唯一标准,JQuery越来越火,得到了很多用户的认可。原因也很简单,它的原则写的很清楚“ write less,do more ”,“写的更少,做的更多” 这句话就是 JQuery 的设计原则,这使其越来越成功,而这种思路我们归结为面向用户的设计思路。

简单的说就是,当你要设计一个通用方法、库或者组件的时候,不应该站在程序本身去思考,而是站在使用者(也就是用户)的角度去思考。假如用户来使用这个方法去开发,他用起来会不会舒服,会不会有些问题让他很头疼,会不会很不爽。一切要面向用户去设计!tangram插件便是基于这种思路去设计的。

二、使用方式设计

如何能够让用户觉得简单好用,是插件设计时面对的一个大难题。最好也是简单到像 tangram2.0 的每一个接口一样,让用户用起来觉得就是很简单。

其设计主要分为两个部分,第一个部分是初始化方式设计,另一部分是调用方式设计。

2.1 初始化方式设计

初始化方式插件默认初始化即为开启状态,用户可以通过传入配置来改变默认行为。如 draggable 设计,如果想让一个 div 直接可以被拖拽,调用方式就是简单的:

1
baidu(‘div’).draggable();

同样selectable的调用方式也是如此:

1
baidu(‘div’).selectable();

但是如果用户有些默认需求,比如想初始化一个已经被限定拖拽范围的draggable,那么可以通过初始化配置默认参数来实现:

1
2
3
baidu(‘div’).draggable({
        range:‘selector’
});

类似的参数及功能还有很多,不再一一赘述。

2.2 调用方式设计

调用上面,我们希望是简单的。所以经过JS小组同学们的讨论,最后摒弃掉了对tangram链条的延续,每次初始化插件后,返回的就是当前插件的一个实例。用户可以直接通过实例方法来调用,也可以直接输出实例,查看都有哪些实例方法,如图1:

alt 1

 图1

而且每个实例方法中,尽可能的又返回了当前的实例,也就是说,在调用过程中,可以是链式的。比如:

1
2
3
4
5
6
var a = baidu(  ‘#selectable1’  ).selectable();
a.cancel().disable();
setTimeout(function(){
    a.enable();
    alert( ‘enable!’ );
},1000);

2.3 tangramDom链条的延续

设计插件时有个问题其实是很纠结的,就是tangram基础库上面的DOM方法是否应该挂载在实例上面。直接通过extend方法,将之前DOM链头上面的方法挂到实例上也是一个办法,但是这样做会带来几个问题:1、重名。插件中的方法名不能和tangram的DOM方法重名,否则会被覆盖;2、结构混乱。用户直接输出实例会看到混乱的方法名称,不知哪些是插件方法,不知哪些是tangramDom方法。

所以基于以上考虑,tangram2.0中设计了一个setBack方法。这个方法会自动挂载一个名称为“getBack”的方法,这个方法会返回当前插件的DOM方法,使tangramDom的链头得以延续下去。

如想要调用 draggable 的 DOM 方法:

1
2
var a = baidu( ‘div’ ).draggable();
a.getBack().css().html()...

其实也就相当于:

1
2
3