天津口腔医院
曾经学过两年地质,知道工程和设计是不分家的,也就是说,工程师可以做设计,设计师也可以做工程,他们有着相同的渊源、相同的知识结构、相同的专业功底,仅仅是业务复杂带来更细的分工,因此,设计师专注于图纸上的构思,工程师则更专注图纸的实现。两者之间似乎不用任何语言便可达到无阻碍的交流。实际项目也是如此,某个项目会首先对设计方案招标,再拿图纸交给工程师去实现,设计师和工程师之间的信息共享唯一的渠道就是,设计图。

简单的几张设计图纸,可以包含一条青藏铁路的所有信息、可以包含原子弹的设计实现、可以包含摩天大楼的任何细节的材料质地成分。。。

这样一张图纸的价格,甚至已经不能用钱来衡量。。。。

反观web设计领域,设计师和工程师之间的信息交换一定要通过嘴,没有严谨的专业词汇、没有量化的规格说明、没有翔实的组件使用说明、更没有系统的图例、以及风格统一的交互流程图,甚至没有文档。。。

工程师听到设计师说的最多的就是:这个XX要更XX一些,那个XX要更XX一些。。。

甚至怀疑交互设计师竟然能成为一种职业。。。

拜托

你能不能设计出一个稿子,让我一看就懂?
你能不能别费那么多口舌给我解释每个细节应该怎么样,我记不住,你的设计应当有翔实的文档和图纸!
你能不能别等我做完了再告诉我xx应当更xx一些?很不专业的说。
我不求你的设计有亮点,不要有歧义就谢天谢地了。
不要强调用户感受,我也是用户,你没有资格比我更代表用户。
。。。

话说回来
交互设计师都很年轻,对他们宽容一些,成长,是需要时间的磨砺的。

以上YY,欢迎拍砖。

[ view entry ] ( 405 views )   |  permalink  |   ( 3 / 193 )
幻灯/Tab/滚动/切换?Y.Slide?一统江湖?看起来很美?
文档已添加:
/cubee/doc/start.php?slide

[ view entry ] ( 731 views )   |  permalink  |   ( 3.1 / 206 )
相信每个前端工程师都有自己喜爱的 javascript框架,说情感也好,道信仰也罢,javascript框架带给人的不仅仅是便捷的开发,更有一种纯粹的逻辑美感,不管是jquery 曼妙的简洁,还是yui魔术般的沙箱,都使我们产生无穷的想象。然而,js框架却又必然无法做到面面俱到的完美无瑕,比如jquery在OO方面做出的让步,以及yui在性能上做的牺牲,无不给人传达一种缺憾美、一种理想的现实主义。今天,我们来看看yui3在框架设计中的这些牺牲和让步,以便让我们更加深刻的理解yui3的全貌,并将其优势发挥至最佳。

1,种子的一步到位 or 颗粒化
所谓种子一步到位是指只要在页面引入一个种子文件的script标签,比如prototype和jquery,只要引入一个prototype.js或 jquery.js就可以了,他们将各自对dom操作和event的封装等等都囊括进一个文件中,并尽力将其做到最小,这样做的好处是显而易见的,使用框架非常简单。然而yui将这些功能做了级别划分和颗粒化设计,从概念上抽象出来“核心”、“工具”和“组件”,每个小功能放在一个文件当中,需要的时候则要自行去引用,yui文档中给出的大量demo都采用这种方法,这种设计显然不像jquery那样对初学者友好,而且使用起来不够傻瓜,为了实现一个小功能,甚至要引入三四个js文件。yui这样做的原因有两个,一是yui实在太大,把所有功能都搞进一个文件中确实有点不靠谱,二是为其动态加载的框架设计做铺垫。

2,手动引入 or 动态加载
往页面中写js的传统方法是,直接将js文件作为script标签路径写在页面中,使用yui也可以这样引入页面,但yui更推荐使用loader进行动态加载。动态加载脚本的渊源很复杂,目前来看主要原因有三,其一,页面中手写js标签无论如何都会占用一个http请求,即使这个请求是一个304,动态加载的文件缓存后则不必发起真实的http请求,其二,动态加载可以实现按需加载,而且可以根据js文件之间的依赖进行去重和排序,手写标签加载js文件则必须让开发者去额外关注一下文件的排序、重复等等,其三,动态加载有利于页面代码的语义化,这使得开发者只关心“需要什么”,而不用去在意“如何得到”。当项目变得越发臃肿,维护成本越来越高的时候,这中小技巧会有不小的好处的。

3,逻辑启动的单一入口 or 沙箱
我们在页面中启动一个js逻辑通常是放在一个类似onDomReady的方法中,如果页面中存在多个逻辑的时候怎么办呢?比如,a实现了逻辑A,页面代码是这样的

<script src="logicA.js" />
<script>
$.onDomReady(function(){
LogicA.start();
});
</script>


这段代码通常写在页面的尾部,这段逻辑所伴随的html代码是埋藏在页面的某处,这时b要在页面中增加逻辑B,b的做法是首先找到尾部的这段代码,然后更改成如下模样:

<script src="logicA.js" />
<script src="logicB.js" />
<script>
$.onDomReady(function(){
LogicA.start();
LogicB.start();
});
</script>


同样,B逻辑所伴随的html代码也是埋藏在页面的某处,这样看来,js逻辑和其伴随的html代码如此分离,以至于到了删减功能的时候,往往删掉 html却忘了删js,或者删掉js忘了删除html,在重用代码的时候也会是个麻烦。同样,在调试的时候,工程师也要打开两个窗口分别关注js和 html,即使这两段代码在同一个文件当中。如此则不如把代码写成这样:

<!–A逻辑的html代码段–>
<script src="logicA.js" />
<script>
$.onDomReady(function(){
LogicA.start();
});
</script>

...

<!–B逻辑的html代码段–>
<script src="logicB.js" />
<script>
$.onDomReady(function(){
LogicB.start();
});
</script>


这种coding写法正是yui所提倡的,也就是所谓的沙箱,每个逻辑包含在一个沙箱中,各司其则互不干扰。当第三者浏览代码的时候也立即明白这就是一个独立的功能块,包含典型的html结构和启动逻辑的js,要重用,整块拷走即可。

4,代码污染 or 沙箱
刚才提到的沙箱可以解决一部分代码污染的问题,新人阅读代码不用再看着乱码般的源码,“瞻前顾后”小心翼翼的寻找html和js的对应关系。但这种写法也存在隐患,现在的前端开发越来越复杂也更多的使用分层,比如底层使用yui,中间层是自定义的工具库,或者再加一个项目的widget组件库,写页面逻辑则是基于这些库进行开发。这样的话,每段逻辑可能写成这个样子:

<!–A逻辑的html代码段–>
<script src="widget.js" /><!–项目的widget库–>
<script src="logicA.js" />
<script>
$.onDomReady(function(){
LogicA.start();
});
</script>


尽管我们可以约定,将项目用到的所有的组件都统一加载进页面中,但当组件越来越多的时候,就出现了上文所说的一步到位和颗粒化之间的矛盾,当每个控件单独占用一个js文件和与之相伴随的css皮肤,一个相对复杂的逻辑就变成了上文所说的手动引入js文件,并随之引入一些显而易见的弊端:

<!–复杂的A逻辑的html代码段,使用了日历,弹层,幻灯–>
<script src="calendar.js" /><!–日历–>
<script src="box.js" /><!–弹层–>
<script src="tabview.js" /><!–幻灯原型–>
<script src="slider.js" /><!–幻灯–>
<script src="logicA.js" />
<script>
$.onDomReady(function(){
LogicA.start();
});
</script>


首先,手写大量的js文件会各自占用单独的http请求,在者,这个场景中,slider.js继承自tabview.js,因此要着重关注他们的顺序,第三,如果别人在页面的其他地方也使用了日历或者幻灯,还要再加两个相同的js标签?其实,说到这里,我们已经可以隐约看到大项目团队开发的影子了,在一个迭代及其频繁的项目中,开发者需要在短的时间内完成一个复杂页面的某个功能的开发,而且不能影响到页面的其他功能,毕竟,每添加一个功能,QA mm们都要将与之牵连的所有功能都要回归,可辛苦了我们的QA mm们。在这种情况下,一个功能的开发可能和同一个页面其他功能的开发相互并行。互相不属于同一个项目组,也不知晓对方的实现。这种模式则是我们经常遇到的多人开发,冲突也大都由此产生,每个功能单独看来是正确的,合并到一起会产生冲突和bug,这时调试bug则需要两个工程师同时进行,很麻烦。甚者,当组件升级了,比如,tabview.js再继承自tab.js,则又要去联系各个工程师,将每个引用tabview.js的地方之前再加上一个 tab.js,很麻烦。我们说,这种多人协作模式所带来的冲突也是代码污染的一种,因为每个人只能掌控类似tms区块那么巴掌大的地方,所组成的最终页面是什么样,都不知道。更何况,这种生猛的引用js,也会阻塞页面加载,占用http请求,影响性能。

鉴于此,yui将js的动态引入机制也并入其沙箱设计之中,我要引用的只是一个名字,比如slider.js,他依赖 tabview.js,tabview.js依赖tab.js,这样我只需引用一个名叫”slider”的东西即可,不用操心他依赖什么,更不用管如何引入到页面中,yui都帮我们搞定:

<script>
TB.addmoudle({
logicA:{
fullpath:’logica.js’,
requires:['slider']
}
}).use(‘logicA’,function(Y){
LogicA.start();
});
</script>


当我们看最终组成的页面的时候,看到的只是埋藏在页面各个角落的这些简短的结构一致的js代码段。很易理解,这点代码也不用像长的代码块压成一行。(更多细节可参照前端弱架构导致的代码污染

5,颗粒化 or http请求数
这的确是一对矛盾,颗粒化带来了项目开发、管理、和代码重用的高效率,却又引入了更多的http请求数,好在yui提供了combo,可以将所有的 http请求合并成一个。只需在YUI引入的时候配置下combo属性即可,高颗粒化的请求数瞬间降低一倍以上。在之前做雅虎关系的时候,在yui2和 yui3pre并存的情况下,可以将请求降低到4个,yui2和3各一个种子,各自一个combo。当然这是在hack掉yui的loader的前提下。yui默认不会合并非yui文件(更多细节可以阅读基于yui的团队开发)。即使这样,我们仍然可以控制我们的http请求数,在不hack yui的情况下,可以解决部分性能问题。

6,懒惰加载 or 即时加载即时执行
上文提到,逻辑依赖沙箱,沙箱依赖的js文件则是延时加载的,这样就导致一个问题,当页面比较庞大的时候,会等待页面js加载完毕才会渲染动作,这样的用户体验不佳,而即时加载即使运行则可以渲染出模块后随即渲染动作,当网速一定的时候,两者看似是一对不可调和的矛盾,yui 动态加载的机制比较折中的处理了这个问题,A逻辑需要a.js,B逻辑需要b.js,A逻辑则只会在a.js加载完成后执行,而不管b.js是否加载完成,而当A需要a.js和b.js的时候,A则需要等待a.js和b.js都加载完成才会执行,B逻辑只需判断当前是否已经加载b.js,如果b.js已经在其他模块中引入进来,B则可以立即执行。但确定的是,所有的js的引入一定是在domReady后执行的,也就是说,不管怎样,动作的渲染一定是在页面html结构出来后才开始执行的,用户体验上还是会有损失。

7,面向接口的设计 or 面向dom的设计
我们知道jquery的插件习惯将所有的动作都加载到一个$(‘#id’)上,使用的时候只要执行类似$(‘#id’).init()即可。这看起来简洁明快,开发者的逻辑的思路也始终没有离开“节点”,很方便理解,而对yui3 的node扩展就不那么方便,从yui3的pre版到正式版,对node扩展的方法在不断的修改(更多细节看这里:扩展yui3 node的定时器),这也可以看出yui设计者在对node扩展性设计时的纠结和苦恼:要不要允许开发者去扩展node节点呢?大概是因为设计者们对prototype先天的弊端心有余悸。目前看来,设计者还没有完全走出纠结,尽管对node扩展相比yui3第一个预览版方便了很多,开发者仍然不能像写jquery插件那样优雅自如的对node进行扩展。相反,zakas却将更多的精力放在了widget接口的设计上,在这一点上,相比jquery,yui3则具有无可限量的优越性,因为在yui3中,组件不仅仅是组件,而是一个有血有肉的生命体,他可以出生,可以成长,可以被改造,可以死亡,组件在这些复杂的运行时环境中自我锤炼,因此,一个复杂页面在yui3的技术体系中,变成了一个由无数组件链接而成的生态系统,这种生物链所带来的设计创新和新视野是其他js框架无论如何也无法超越的。关于yui3的组件开发更多细节可以参照:基于yui3的组件开发1 和 克军在D2上的分享《从yui2到yui3看前端的演变》

8,苗条的身材 or 庞大的身躯
说到这里,大概会有很多人拍砖。其实jquery和yui同属两类不同的js框架,一个苗条纤细,一个身重如山,两者之间其实没有什么水深火热,只是使用范围不同罢了,类似jquery的轻框架的使用范围是博客级别的小网站,尤其适合单人开发,代码写一次不再修改,而且很适合初学者学习使用,给初学者带来自信。yui则使用与企业级的项目中的团队开发,项目维护周期远远超过开发周期,因此yui性能一定比不过jquery,jquery的续航能力也一定不如yui,没有最优秀,只有最适合。当然这自然也挡不住我个人对迷人的jquery的喜爱,只要我们能从各个js框架学到东西,能提高自己做前端架构的能力,就ok。

说了这么多,其实只有一个观点,人无完人,框架无完框架,缺憾之处必有权衡。以上YY,欢迎拍砖!

[ view entry ] ( 807 views )   |  permalink  |   ( 3 / 209 )
终于赶在年前发布了一个版本!前期的积累永远不是什么坏事,切记不要冒进,cssreset基于yui,看不懂的话可以看看YUI的reset。



这里是代码级的手册草稿:
http://uedmagazine.com/cubee/doc/start.php

[ view entry ] ( 295 views )   |  permalink  |   ( 3 / 212 )
之前写过一个日历控件,这个日历是仿照jquery的日历写的一个yui3版本,比较简单,只支持单页,也不支持范围选择,只当练手用,代码也比较简单。在cubee项目中要做一个完整的日历,cubee的开发中我负责弹层和日历,弹层比较简单,用yui3的overlay就可以搞定,日历比较麻烦,因为ID和VD并没有给我什么有价值的交互流程的参考。VD图只是一个样子,日历中的交互逻辑要复杂超过我们想象,其实,yui2提供的日历控件已经堪称完整强大了,但其接口还不是那么简洁,而且这么强大的功能仍然不能做到UI和功能的完美统一,比如弹出日历是放在一个弹框中的,而且弹出日历的结束操作一定是点击“确定”按钮才生效,在比如静态日历的事件回调仍然使用setCallBack方法,当然,yui2的日历的html结构很典型,因此定制皮肤也比较容易。cubee的开发思路是做一套实用好用的组件,因此日历控件的基本要求就是,1,实用,2,好用。

根据UI设计,日历的原型骨架是这样的,这个是切好的html,显而易见的,子日历个数应当是可以定制的,每个子日历也相当于一个小的日历。



Demo

从图中可以看到,日历的行为具有高度内聚的特点,可以将日历看成一个黑盒,所有的操作在黑盒内进行,通常并不会和日历的外界上下文发生联系,唯有在初始化或者绑定回调的时候有与外界的互动,更重要的,在日历的黑盒操作中包含大量的模式化的行为,这些行为抽象出事件,由这些事件的发生来触发回调。也就是说,日历从外界获取初始化参数并渲染成型,日历上的事件触发回调。日历的架子也可以根据这种思路搭建起来。

再来看细节,考虑到日历灵活的可配置,需要将日历进行拆分成外框加内核,外框负责对黑盒进行包装,用来管理事件和基本的数据结构,内核用来渲染单个子日历的ui,渲染出的ui由外框链接起来。所谓内核是日历逻辑的主题部分,主要的ui部分和事件的发生也在这里。在这里,Y.Calendar用来命名外框,Y.Calendar.Call用来命名内核。使用者只接触到Y.Calendar:



其中,外框Y.Calendar所包含的逻辑包括,buildDataStructor(根据参数准备数据),buildEventCenter(事件中心),render(渲染)。Y.Calendar.render是一个抽象的渲染,这个渲染过程中要生成各个Y.Calendar.Call的实例,具体的ui渲染交给Y.Calendar.Call.randerUI去执行。日历内核Y.Calendar.Call所包含的逻辑有,renderUI(渲染UI),buildEvent(生成内部事件),这两个方法放在一个render中,方便对外(外框)做统一调用。

此外,如果一个Y.Calendar中包含多个Y.Calendar.Call实例,实例之间是如何通讯的?因为每个子日历的行为要看起来步调一致。其实多个子日历之间并无直接通讯,是通过父框做桥接,每个事件直接通知到父框,由父框去render其包含的每个子日历,这样的话可以把子日历的行为按照固定的模式抽象出来。



这样,一个完整日历的结构就基本定型了,接下来需要做的就是针对这些接口编程了。这里,YUI提供的自定义事件对简化代码很有帮助,另外,YUI2的日历的一些比较冗余的参数也可以去掉,这样就可以把接口的格式提炼的更加简洁,使用起来方便顺手,特别是对于习惯yui的人来说,非常容易理解。

日历控件的设计思路大抵就是这样,看看demo

Y.Calendar Demo

以上~

[ view entry ] ( 1321 views )   |  permalink  |   ( 3 / 217 )

<<First <Back | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Next> Last>>