还说网易旗下免费邮(163、126、Yeah.net)的js代码

      经过大致浏览163免费邮(126、Yeah.net和163用的js其实大致一样,只是页面和css不一样)的核心js后(该文章有个上下文,请看我之前的几篇文章),个人感觉其js写法还存在改善的空间。所以本文试图从个人的理解角度(本文只是试图要改善其js写法,并不是站在设计得更好的角度,所以有些想法依然沿袭其做法,也许还存在更好的做法),用prototype库来重构163免费邮的核心js,具体函数细节并不予实现,待日后再抽出时间,将其中常用的功能模块重构成组件(已实现部分),有兴趣的同学再保持关注哦:)

      在这之前,试想,如果你是网易163免费邮的js设计者,如此UI的用户体验,你会怎么来组织和架构你的js呢?从OOP的角度来想,应该是先把系统分好模块,然后各个模块至少独立出一个类来管理这个模块。网易的js设计者是这样来划分这个系统的模块:文件夹管理模块(操作对象为收件箱、草稿箱等,如对他们进行清空、重命名等操作)、文件夹模块(和前一模块的区别在于操作对象是文件夹下的邮件条目,其主要职责为对该文件夹下的条目进行管理。 主要包含对其邮件条目的操作有:删除、移动、收藏、状态设置、标签等)、欢迎模块(即登陆邮箱后的第一界面具有的功能管理)、阅读界面模块(主要包含阅读邮件时的一系列操作)、发送界面模块(主要包含撰写邮件时的一系列操作)、外部链接模块(主要对应于左边邮件服务栏目的超链接等)、通讯录模块等。

      网易js设计者把以上所有模块都统一放置于mainmodule.js(这种做法实在是不太可能,可能是我推测错误?!),个人觉得这样明显不合理,建议把其按各个模块进行拆分,独自命名一个js文件,如Folder.js、FolderMain.js等,方便维护,避免冗长,尽管有人建议减少js文件有利于节省带宽。详细请见js附件(Compose.js、Folder.js、FolderMain.js、OutLink.js、Read.js、Send.js、Welcome.js)。既然这么多个模块都是在右下角进行切换,是不是可以考虑做个类似模块管理者来对这些模块进行管理呢,比如切换等,而且这些模块肯定具有某些公共特性,所以我建议为各个模块增加一个父类。所以,如果是我,我会增加2个类——BaseModule和ModuleManager。详见附件(BaseModule.js、ModuleManager.js)。

      另外,engine.js也是太过于臃肿,建议分出这样几个类——CommonControl.js(工具类)、CoremailManager.js(核心邮件管理者,建议可以把getCMData方法移到工具类)、GlobeEngine.js(全局发动机,所有全部的变量都保存到该类中)、HistoryManager.js(暂时没研究,貌似为了回退按钮服务),然后最后在这样来调用你的js:

document.observe('dom:loaded', function() {
	window.CC = new CommonControl();
	window.CM = new CoremailManager();
	window.GE = new GlobeEngine();
	window.HM = new HistoryManager();
	window.MM = new ModuleManager();
	/**
	 * 将各个模块注册到模块管理者
	 */
	MM.registModule("folderMain", new FolderMain());
	MM.registModule("folder", new Folder());
	MM.registModule("read", new Read());
	MM.registModule("send", new Send());
	MM.registModule("outLink", new OutLink());
	MM.registModule("compose", new Compose());
	MM.registModule("welcome", new Welcome());
	// 之后便如是调用compose对象——MM["compose"]或MM.compose
	});

当然,最后别忘记了prototype库的prototype.js。

以上,对整体js架构和组织提了自己的意见,有兴趣的可具体看附件的js。

      另外,大致看了一下其细节部分js的写法,我也提几个意见:

1.163免费邮右上角的“数据处理中,请稍后...”,即传说中经典的spinner,其代码的做法每做一次ajax请求操作都先调用show(),然后再调用hide(),如此甚是麻烦,应该在ajax请求的全局设置,代码类似:

Ajax.Responders.register({
	  onCreate: function() {
        if($('spinner') && Ajax.activeRequestCount>0)
          $('spinner').show();
        },
	  onComplete: function() {
        if($('spinner') && Ajax.activeRequestCount==0)
          $('spinner').hide();	  
        }
	});

 即在ajax上注册全局的监听器,维护一个进度指示器的显示和隐藏,免去每个方法都可见对spinner的操作。

2.163免费邮页面上嵌入了一些事件的js,如onclick事件等,为了遵从不唐突的js优良传统做法,我们利用prototype里的事件注册处理器,将html代码与js尽可能地剥开,如document.observer("dom:loaded",start()),$("selectAll").observe("click",toggleAll)等。

3.163免费邮有自己的封装库engine.js,但其中心思想还是在模仿prototype(其源代码中模仿prototype清晰可见),但是又没有模仿到家,一些prototype非常有用而简易的api没有模仿到,所以,这里建议,既然要模仿,但又做得不比prototype好,那为什么不直接用prototype呢?比如文件夹收件箱中checkbox的全选操作,如果借助于prototype,代码将大大减少,如:

//勾选操作
function toggleAll(event,isChecked){
event.stop();
$("table").select("input[type=checkbox]").each(function(checkbox){
checkbox.checked = isChecked;
});
}
//全选按钮
$("selectAll").observe("click",toggleAll.bindAsEventListener(this,true));
//去全选按钮
$("deselectAll").observe("click",toggleAll.bindAsEventListener(this,false));

 借助于prototype强大的select函数,根据css选择器来获取元素(当然,其他框架也有类似api,比如jquery,这里并不是要比较prototype好,还是jquery)。而我163中的js看到了比以上代码还要长得多的代码却也只实现同样的功能。

4.163免费邮主界面除了上部和左部是静态的html,右下角的模块,其hmtl都是在js中动态生成的。所以在js中会看到很长的html拼凑,我想163免费邮的同学当时调试维护肯定花了不少时间吧?呵呵,就像动态拼凑sql语句那样,如果够长沟复杂,的确很容易出错和难维护。而且我发现其拼凑的html的格式有些是几乎一样的,只是数据不一样。所以建议可以考虑一下prototype的template,其主要思想是定义个html模板,然后给这个模板动态赋值,填充数据,肯定可以省力不少。

5.发现网络带宽有限的情况下,进入邮箱速度比较慢,建议不妨尝试在js数据加载的能力方面进行一些改进(特别是之前的一个版本,进入通讯录时,默认把“所有联系人”这个组的数据加载进来,明显特别慢,还有,点击写信进入发送界面时,右边通讯录树显示慢)?个人觉得可以改进的一个点——当数据量大时,如果你需要遍历,那么用js的普通循环替代你们封装的迭代函数——Hashtable:each,即Hashtable对象中的each方法。普通循环代码类似:

var item;
for(var i = 0,len = data.length;i!=len;++i){
item = data[i];
//处理item
}

 首先,它在循环体外声明item变量,所以每次循环都没有分配和释放的开销;其次,它缓存了集合的长度,避免了在每次循环的时候再计算,第三,它使用了前置的++操作,避免了操作数的复制。

6.最后建议建立一个面向对象的体系,添加自己的Object.extend方法,尽管它不是必须的,但是它会让你的代码更加易懂。我在163免费邮的js中看到,Read对象对ModuleStatus的扩展是纯粹的方法复制(即为了实现Read继承于ModuleStatus,将ModuleStatus的方法全部复制一遍到Read对象中,当然,这和prototype做法是一样的)。如果能看到类似以下代码是不是会更加明了呢?

//Read对象继承于BaseModule
var Read = Class.create(BaseModule,{//具体实现...});

 7.163免费邮的js前台数据传入到后台的格式为 xml 格式,个人觉得解析xml相对json较为复杂, 建议采用json,忘记xml,目前无论是java还是其他比如grails都集成了方便的json解析库,非常方便变可获取到前台传入的数据对象,从而更加OO。

8.也许还有更多……

      最后,因为个人能力和见解有限,可能存在某些理解错误,毕竟是局外人。以上建议只代表个人意见,仅供大家谈笑,欢迎拍砖:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值