jquery下组织javascript代码(js函数化)


Posted in Javascript onAugust 25, 2010

从神奇的"$"函数开始
"$"函数将在文档加载完成之后为一个指定的button 绑定事件,这些代码在单个网页中工作正常。但是如果我们还有其它的网页,我们将不得不重复这个过程。

<a href="javascript:;" id="sayHello">Say Hello</a> 
<script type="text/javascript"> 
//when dom ready, do something. 
//bind click event to a button. 
$(function(){ 
$('#sayHello').click(function(){ 
alert('Hello world!'); 
}); 
}); 
</script>

如果我们需要另一个行为的button怎么办?比如象这样:
<a href="javascript:;" id="sayUnlike">Unlike it</a> 
<script type="text/javascript"> 
//when dom ready, do something. 
//bind click event to a button. 
$(function(){ 
$('#sayUnlike').click(function(){ 
alert('I unlike it.'); 
}); 
}); 
</script>

接下来,更多的问题出现了,我们需要很多这样的button, 这好象也不难。
<a href="javascript:;" class="sayUnlike">Unlike it</a> 
<script type="text/javascript"> 
//Change to a class selector to match all the button elements. 
$(function(){ 
$('.sayUnlike').click(function(){ 
alert('I unlike it.'); 
}); 
}); 
</script>

一个页面里面同种出现了两种button ......
<a href="javascript:;" class='sayHello'>Say Hello</a> 
<a href="javascript:;" class="sayUnlike">Unlike it</a> 
<script type="text/javascript"> 
$(function(){ 
$('.sayHello').click(function(){ 
alert('Hello world!'); 
}); 
$('.sayUnlike').click(function(){ 
alert('I unlike it.'); 
}); 
}); 
</script>

但是呢,不是所有的页面都会用到这两种的button,为了不在页面上使用额外的选择器,我们要作一些必要的调整,因为基于class的选择器的性能相对于id选择器开销很大,需要遍历所有dom元素,并使用正则表达式匹配class属性来选定满足条件的元素。
<? if($page == 'A'){?> 
<script type="text/javascript"> 
$(function(){ 
$('.sayHello').click(function(){ 
alert('Hello world!'); 
}); 
}); 
</script> 
<? } ?> 
<? if($page == 'B'){?> 
<script type="text/javascript"> 
$(function(){ 
$('.sayUnlike').click(function(){ 
alert('I unlike it.'); 
}); 
}); 
</script> 
<? } ?>

我们的项目功能越来越复杂,经过一段时间以后,变成了这个样子, quick but dirty......
<? if($page == 'A' or $page == "C" and $page is not "D"){ ?> 
<script type="text/javascript"> 
...... 
</script> 
<? } ?> 
<? if($page == "B" or $page == "E" and $page is not "X"){ ?> 
<script type="text/javascript"> 
..... 
</script> 
<? } ?> 
<? if($page == "B" or $page == "E" or $page == "C"){ ?> 
<script type="text/javascript"> 
..... 
</script> 
<? } ?>

这真是太糟糕了,我们需要在一个页面上加载许多个代码片断才能绑定所有的事件,如果我们再将不同的代码分装入多个js文件中这将增加多个页面资源的http请求,不论是管理还是用户体验都将面临挑战,我们需要找到一个更佳的解决方案。
既然 class selector 的开销这么大,我们能不能在一次扫描中绑定所有的事件?我们可以尝试一下:
<script type="text/javascript"> 
//Register global name space. 
var Yottaa = Yottaa || {}; 
Yottaa.EventMonitor = function(){ 
this.listeners = {}; 
} 
//Bind all event. 
Yottaa.EventMonitor.prototype.subscribe=function(msg, callback){ 
var lst = this.listeners[msg]; 
if (lst) { 
lst.push(callback); 
} else { 
this.listeners[msg] = [callback]; 
} 
} 
// Create the event monitor instance. 
var event_monitor = new Yottaa.EventMonitor(); 
function load_event_monitor(root){ 
var re = /a_(\w+)/; //using a regular expression to filter all event object. 
var fns = {}; 
$(".j", root).each(function(i) { 
var m = re.exec(this.className); 
if (m) { 
var f = fns[m[1]]; 
if (!f) { //如果事件处理函数不存在则创建函数对象. 
f = eval("Yottaa.init_"+m[1]); 
fns[m[1]] = f;//调用绑定函数. 
} 
f && f(this); 
} 
}); 
} 
$(function(){ 
// when dom ready, bind all event. 
load_event_monitor(document); 
}); 
//Here is 2 sample components. 
Yottaa.init_sayhello = function(obj){ 
$(obj).click(function(){ 
alert('Hello world!'); 
}); 
} 
Yottaa.init_unlike = function(obj){ 
$(obj).click(function(){ 
alert('I unlike it.'); 
}); 
} 
</script>

我们的DOM元素这样写:
<a href="javascript:;" class="j a_sayhello">Say Hello</a>
<a href="javascript:;" class="j a_unlike">Say Unlike</a>

这样看起似乎好多了,我们只需要在页面加载的时候执行一次class selector(在上面的代码中就是所有'.j'的元素)就可以找到所有需要绑定事件的元素,具体绑定哪一个组件由 class 名称里面的 a_xxx 来决定,对应着 Yottaa.init_xxx,并将当前元素的引用作为参数传入事件逻辑中。
在这个处理模式下,我们不需要再次手动编写事件处理的逻辑并将它放到 $(function(){ .... }); 这样的初始化函数中,所有我们要做的事情仅仅是给组件的“容器”加上两个 class: "j a_XXX"程序即可帮我完成事件绑定工作,是不是很 cool ?象常用的展开/折叠效果,全选/反选效果, tab切换以致于一些其它的简单功能都可以使用这种方式。难道这就是传说中的银弹?不,事情没那么简单,我们应该看到这种处理方式一些弱点:
不能给组件传递初始化参数。
不能体现出组件的包含关系,也不能利用继承和多态等面向对象的特性使程序更容易编写和理解。
对于部分具体关联关系的组件在处理上略显麻烦,没有合理的事件通知机制。
我们来看看第一条:关于参数的传递,在许多场景下对于多个条目的列表,对应每一个条目我们一般会给元素分配一个唯一一的id,这些元素的行为类似,不同之处只是服务器端的编号不同,比如一个留言列表或者是一个产口列表。我们可以利用id属性为我们作一些事情,看下面的代码,我们用id属性把条目对应的服务器端编号告诉javascript,并在接下来的事件逻辑处理中作为服务器回调函数参数的一部分发回服务器端。

<script type="text/javascript"> 
Yottaa.init_sampleajax = function(obj){ 
$(obj).click(function(){ 
var component_id = $(this).attr('id').split('-')[1]; 
$.get('/server/controller/method', {id: component_id}, function(data){ 
if(data){ 
alert('Message from server: ' + data ); 
} 
}); 
}); 
} 
</script> 
<a href="javascript:;" class='j a_sampleajax' id='item-a'>Show server message. </a> 
<a href="javascript:;" class='j a_sampleajax' id="item-b">Another button with same action but different server side identifier.</a>

在更复杂的一些场景中我们可以利用页面上的inline code给组件传递一些必要的信息。
Yottaa.globalConst = { 
User:{ 
familyName: "Jhone", 
givenName: 'bruce' 
}, 
Url:{ 
siteName: 'yottaa.com', 
score: 98 
} 
} 
Yottaa.componentMetaData = { 
compoment_id_1:{ ...... }, 
component_id_2:{ ...... } 
};

上面讨论了一种可能的代码组织办法,但是并非适用于所有的项目,我们要做的是:针对于目前的现状,找到一个在代价比较小的重构方案。我们考虑如下几点:
分离元素的事件绑定代码和组件代码:组件代码包括jquery库,相关扩展插件,以及我们自己编写的小部件,如chartbox等内容。
事件绑定及处理逻辑:按不同的组件划分为多个模块,每个模块放入一个function中。
页面需要指定哪些模块要在本页面上初始化,提供一个列表交由全局的事件绑定器统一处理。
下面来演示一下部分代码:
<script type="text/javascript"> 
function init_loginPanel = function(){ 
var container = $('login_panel'); 
$('#login_button').click(function(){ 
...... 
}); 
} 
function init_chart = function(){ 
...... 
} 
//global static init method 
Yottaa.initComponents = function(components){ 
for(var i = 0;i<components.length;i++){ 
if(typeof window[components[i]] == 'Function'){ 
window[components[i]](); 
} 
} 
} 
// above is in the 'all-in-one' assets file which is compressed to one file in production. 
var components = ['init_loginPanel', 'init_chart']; 
var metaData = { 
loginPanel: {}, 
chart: {}, 
...... 
}; 
$(function(){ 
Yottaa.initComponents(components); 
}); 
//here is inline script on the page. 
</script>
Javascript 相关文章推荐
让AJAX不依赖后端接口实现方案
Dec 03 Javascript
通过jQuery源码学习javascript(三)
Dec 27 Javascript
JavaScript实现GriwView单列全选(自写代码)
May 13 Javascript
简单的邮箱登陆的提示效果类似于yahoo邮箱
Feb 26 Javascript
javascript限制文本框输入值类型的方法
May 07 Javascript
jQuery绑定事件-多种实现方式总结
May 09 Javascript
深入理解jquery跨域请求方法
May 18 Javascript
AngularJS国际化详解及示例代码
Aug 18 Javascript
vue页面跳转后返回原页面初始位置方法
Feb 11 Javascript
Angular如何在应用初始化时运行代码详解
Jun 11 Javascript
微信小程序上传图片到php服务器的方法
May 23 Javascript
解决vue+elementui项目打包后样式变化问题
Aug 03 Javascript
jquery实现居中弹出层代码
Aug 25 #Javascript
jquery下实现overlay遮罩层代码
Aug 25 #Javascript
在网页中使用document.write时遭遇的奇怪问题
Aug 24 #Javascript
javascript下string.format函数补充
Aug 24 #Javascript
javascript下利用arguments实现string.format函数
Aug 24 #Javascript
基于jQuery的淡入淡出可自动切换的幻灯插件
Aug 24 #Javascript
js null,undefined,字符串小结
Aug 21 #Javascript
You might like
PHP中使用unset销毁变量并内存释放问题
2012/07/05 PHP
php的一个简单加密解密代码
2014/01/14 PHP
PHP中的一些常用函数收集
2015/05/26 PHP
PHP实现适用于文件内容操作的分页类
2016/06/15 PHP
PHP 闭包详解及实例代码
2016/09/28 PHP
php empty 函数判断结果为空但实际值却为非空的原因解析
2018/05/28 PHP
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
关于不同页面之间实现参数传递的几种方式讨论
2017/02/13 Javascript
vue2 中如何实现动态表单增删改查实例
2017/06/09 Javascript
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
Angular项目从新建、打包到nginx部署全过程记录
2017/12/09 Javascript
js中的 || 与 &amp;&amp; 运算符详解
2018/05/24 Javascript
vue使用v-if v-show页面闪烁,div闪现的解决方法
2018/10/12 Javascript
layui默认选中table的CheckBox复选框方法
2019/09/19 Javascript
vue-video-player 解决微信自动全屏播放问题(横竖屏导致样式错乱问题)
2020/02/25 Javascript
python使用win32com在百度空间插入html元素示例
2014/02/20 Python
Python实现Mysql数据库连接池实例详解
2017/04/11 Python
Python基础教程之利用期物处理并发
2018/03/29 Python
Python 线性回归分析以及评价指标详解
2020/04/02 Python
基于python3.7利用Motor来异步读写Mongodb提高效率(推荐)
2020/04/29 Python
Python批量处理csv并保存过程解析
2020/05/16 Python
Django实现随机图形验证码的示例
2020/10/15 Python
html5组织文档结构_动力节点Java学院整理
2017/07/11 HTML / CSS
大学新生军训个人的自我评价
2013/10/03 职场文书
晚会主持词开场白
2014/03/17 职场文书
《祁黄羊》教学反思
2014/04/22 职场文书
申论倡议书范文
2014/05/13 职场文书
艺术学院毕业生自荐信
2014/07/05 职场文书
通信工程求职信
2014/07/16 职场文书
上课睡觉检讨书300字
2014/11/18 职场文书
投标售后服务承诺书
2015/04/29 职场文书
2015年税务稽查工作总结
2015/05/26 职场文书
2015年党风廉政建设个人总结
2015/08/18 职场文书
Python多线程 Queue 模块常见用法
2021/07/04 Python
Go 内联优化让程序员爱不释手
2022/06/21 Golang
Docker部署Mysql8的实现步骤
2022/07/07 Servers