位置:海鸟网 > IT > JavaScript >

轻便型全站javascript部署

问题的提出

一年前刚开始做项目的时候,我对于前台技术还刚刚入门,用jquery写点小打小闹的交互效果还是没太大问题,但是要把所有这些效果干净,整洁的部署到全站,对我来说就有点头疼了.由于网站页面虽说不是特别多,但也有二三十个,如果每个页面写一个单独的js文件或者直接把js写在页面内,是不利于维护和有损前台性能的.按照yahoo的前台性能提升建议,应该尽量减少文件个数.于是我决定想办法把除了jquery库及一些插件之外自写代码全部写到一个文件之中.虽然可能有时候某些页面载入的js会有用不到的代码,但是这样做对于一个中等规模的网站来说有如下的性能优势:

这样的部署,可以谓之'轻便'.现在的问题就是,如何组织这个文件,让其尽量有条理. 当然当时的我还是菜鸟,写js的程度还在只会使用jquery的阶段,对于扩展jquery是一无所知,更不用说js闭包,用js模拟其他语言的OOP使用,以及设计模式这些比较专业的技巧了(其实现在对这些技术还在学习当中). 我不可能凭空想出一个好的办法来,所以就开始参考其他性能比较出色的web2.0站的js代码. 国外网站(如digg,netvibes)的js都用packer之类的东西加了密,人读起来很困难,于是又转向国内,看了看校内等,js文件好多,毕竟是大型网站不适合.后来找到豆瓣,发现性能性能相当出色,而且当时的js也没加密,只有三个文件jquery.js,suggest.js以及douban.js.其中最后一个文件是值得参考的.

豆瓣代码研究

当时读豆瓣的代码也费了不少劲. 我发现在豆瓣的Html中有些元素的类(class)名称很特别,比如(注意class属性的值)


而且这些元素一般都是有js来增强交互效果的,比如表单元素,推荐按钮等;在douban.js中也存在很多与上述一些元素类名称命名一致的变量,比如

Douban.init_search_text = function(o){
//这里是相关代码
}

于是我就想,豆瓣应该是这样想的:把js当CSS来用,当赋予某些元素特定的类名称时,该元素就会拥有相应的js特性,比如上面说的input元素拥有类名称a_search_text,于是就拥有了Douban.init_search_text这个变量(或者说函数)赋予的js特性.这是怎么实现的呢?为了方便说明,把douban.js简化如下,省略了细致末节,大家可以大致看出主干:

//------第一段------
var Douban = new Object();
Douban.EventMonitor = function(){
this.listeners = new Object();
}
Douban.EventMonitor.prototype.broadcast=function(widgetObj, msg, data){/*代码省略了*/};
Douban.EventMonitor.prototype.subscribe=function(msg, callback){/*代码省略了*/};
Douban.EventMonitor.prototype.unsubscribe=function(msg, callback){/*代码省略了*/};

//------第二段------
var event_monitor = new Douban.EventMonitor();
function load_event_monitor(root) {
var re = /a_(\w+)/;
var fns = {};
$(".j", root).each(function(i) {
var m = re.exec(this.className);
if (m) {
var f = fns[m[1]];
if (!f) {
f = eval("Douban.init_"+m[1]);
fns[m[1]] = f;
}
f && f(this);
}
});
}
$(function() {
load_event_monitor(document);
});

//------第三段------
Douban.init_evc = function(o) {/*...*/};
Douban.init_enb = function(o) {/*...*/};
Douban.init_folder_n = function(o){/*...*/};
Douban.init_unfolder = function(o){/*...*/};
...


可以把代码分为三段:

山寨版的代码以及小技巧

读懂豆瓣的代码后,就开始部署自己的山寨版代码,实施方法大致差不多(只不过把Douban对象换成了XM),就不再赘述,文章结尾有demo网址.这里介绍用这种方法的几种技巧.

  • 可复用的confirm框.

    XM.init_confirm = function(o) {
    if(!o.name){
    $(o).click(function(){
    var text = o.title || $(o).text();
    return confirm("确定要"+text+"?");
    });
    }

  • 使用示例

    <a href="/delete" title="删除这个帖子" class="j x_init_confirm">删除</a>

    点击这个链接后会弹出确认框,提示"确定要删除这个帖子吗?",点击确定将前往删除页面,点"取消"可以取消操作

  • 整理变量. 原理很简单,在XM对象下再建立命名空间来分类相应变量,比如

    XM.URL = {
    user_avatar: '/Content/i/ud.gif',
    group_avatar:'/Content/i/gd.gif',
    topic_thumb: '/Content/i/tnd.gif'
    };

  • 其他技巧会在本系列的后续文章中穿插提到. 大家有什么疑问和建议,欢迎评论,希望共同提高!

    douban.js在这里: 下载