ID #6527

web前台技术学习总结(3)-轻便型全站javascript部署

问题的提出

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

js文件数量很少,浏览器对 服务器的请求次数会大大减少,节约了服务器的资源;

由于几乎每个页面 要载入的js文件都相同,这样在首页载入后,再访问其他页面,浏览器可以直接从 缓存中读取全部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属性的 值)

<input type="text"  name="search_text" class="j a_search_text  greyinput" autocomplete="off"/>

而且这 些元素一般都是有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的对象,为其添加了EventMonitor的属性. 这个Douban元素很重要,后来知 道这样做的好处是这个Douban元素能作为命名空间,让自定的变量不会'污染 '全局命名空间(就是window对象),最近才知道,这样的设计模式叫做 singleton. 至于EventMoniter属性其实是一个构造函数,用来创建的对象能在页 面范围内用observer的设计模式实现对事件的订阅 (subscribe),发布 (publish).不过在这一版本的douban.js文件中好像很少有这个东西的使用.

第二段很精彩,正是load_event_monitor函数实现了'把js当CSS来用 '.具体实现是这样的:当一个html元素同时拥有名称为j和以 a_开头的类时, 在DOM之后js就执行相应的Douban对象的以init_开头的属性.比如:当input元素 拥有class=j a_search_text属性时,js就会eval相应的 Douban.init_search_text().在 load_event_monitor内部,用re正则表达式去匹 配出要找的元素属性,然后用eval来执行相应的代码;这个函数唯一的参数root就 是待加入js特性的元素. 在DOM完成载入后,douban.js把document作为 load_event_monitor的参数运行,让整个文档所有待加入js特性元素初始化.

第三段就是初始化相应元素的代码,也就是日后需要维护的地方.这里的 代码比较整洁,都是以Douban.init_开头,看到变量名称,其功能就一目了然.

山寨版的代码以及小技巧

读懂豆瓣的代码后,就开始部署自己的 山寨版代码,实施方法大致差不多(只不过把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'
};

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

Demo地址(也就是项目地址):鲜芒(http://www.xianmang.com/) (欢迎拍 砖)

douban.js在这里:

本文配套源码


2011-07-01 18:54
阅读:
I'm VC , Just U know Y
本站部分文章来源于互联网,版权归原作者所有。

延伸阅读:

使用jQuery和PHP构建一个受Ajax驱动的Web页面

使用Grails与jQuery创建Web Calendar

jquery调用WebService和WebService输出JSON

jQuery Ajax方法调用Asp.Net WebService的详细例子

web前台技术学习总结(1)-CSS实现全浏览器兼容的