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 相关文章推荐
jquery 简单导航实现代码
Sep 11 Javascript
打印json对象的内容及JSON.stringify函数应用
Mar 29 Javascript
基于JavaScript 类的使用详解
May 07 Javascript
js中document.write使用过程中的一点疑问解答
Mar 20 Javascript
jQuery.lazyload+masonry改良图片瀑布流代码
Jun 20 Javascript
JavaScript事件委托技术实例分析
Feb 06 Javascript
详解基于angular路由的requireJs按需加载js
Jan 20 Javascript
使用Node.js实现RESTful API的示例
Aug 01 Javascript
vue实现新闻展示页的步骤详解
Apr 11 Javascript
vue+mock.js实现前后端分离
Jul 24 Javascript
JS计算斐波拉切代码实例
Sep 12 Javascript
JavaScript中的执行环境和作用域链
Sep 04 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下通过exec获得计算机的唯一标识[CPU,网卡 MAC地址]
2011/06/09 PHP
PHP网站备份程序代码分享
2011/06/10 PHP
ini_set的用法介绍
2014/01/07 PHP
Joomla数据库操作之JFactory::getDBO用法
2016/05/05 PHP
php实现微信支付之现金红包
2018/05/30 PHP
对laravel的csrf 防御机制详解,及form中csrf_token()的存在介绍
2019/10/24 PHP
为什么要在引入的css或者js文件后面加参数的详细讲解
2013/05/03 Javascript
javascript获取form里的表单元素的示例代码
2014/02/14 Javascript
js中实现多态采用和继承类似的方法
2014/08/22 Javascript
JavaScript实现搜索框的自动完成功能(一)
2016/02/25 Javascript
jQuery判断checkbox选中状态
2016/05/12 Javascript
jquery html5 视频播放控制代码
2016/11/06 Javascript
微信小程序 Template详解及简单实例
2017/01/05 Javascript
PHP自动加载autoload和命名空间的应用小结
2017/12/01 Javascript
详解刷新页面vuex数据不消失和不跳转页面的解决
2018/01/30 Javascript
Angular6笔记之封装http的示例代码
2018/07/27 Javascript
说说如何利用 Node.js 代理解决跨域问题
2019/04/22 Javascript
解决mui框架中switch开关通过js控制开或者关状态时小圆点不动的问题
2019/09/03 Javascript
IE11下CKEditor在Bootstrap Modal中下拉问题的解决
2019/09/25 Javascript
JavaScript实现手风琴效果
2021/02/18 Javascript
python3.x 将byte转成字符串的方法
2018/07/17 Python
利用Python将每日一句定时推送至微信的实现方法
2018/08/13 Python
解决python中 f.write写入中文出错的问题
2018/10/31 Python
python 实现调用子文件下的模块方法
2018/12/07 Python
pandas的连接函数concat()函数的具体使用方法
2019/07/09 Python
OpenCV Python实现拼图小游戏
2020/03/23 Python
python神经网络编程实现手写数字识别
2020/05/27 Python
基于Python下载网络图片方法汇总代码实例
2020/06/24 Python
CSS3 选择器 伪类选择器介绍
2012/01/21 HTML / CSS
细说CSS3中box属性中的overflow-x属性和overflow-y属性值的效果
2014/07/21 HTML / CSS
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
餐厅筹备计划书
2014/04/25 职场文书
自愿离婚协议书范文2014
2014/10/12 职场文书
大学生村官工作总结2015
2015/04/09 职场文书
2015年妇联工作总结范文
2015/04/22 职场文书
民事申诉状范本
2015/05/20 职场文书