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 相关文章推荐
通过ifame指向的页面高度调整iframe的高度
Oct 05 Javascript
jQuery之自动完成组件的深入解析
Jun 19 Javascript
关于img的href和src取变量及赋值的方法
Apr 28 Javascript
事件委托与阻止冒泡阻止其父元素事件触发
Sep 02 Javascript
node.js中的console.error方法使用说明
Dec 10 Javascript
JQuery简单实现锚点链接的平滑滚动
May 03 Javascript
ES6学习笔记之正则表达式和字符串正则方法分析
Apr 25 Javascript
详解Vue.js基于$.ajax获取数据并与组件的data绑定
May 26 Javascript
vue.js 底部导航栏 一级路由显示 子路由不显示的解决方法
Mar 09 Javascript
JS实现滑动导航效果
Jan 14 Javascript
Node.js API详解之 net模块实例分析
May 18 Javascript
Vue3 的响应式和以前有什么区别,Proxy 无敌?
May 20 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数组循环操作详细介绍 附实例代码
2013/02/03 PHP
PHP结合jQuery.autocomplete插件实现输入自动完成提示的功能
2015/04/27 PHP
PHP封装的Twitter访问类实例
2015/07/18 PHP
UI Events 用户界面事件
2012/06/27 Javascript
微信公众号 摇一摇周边功能开发
2016/12/08 Javascript
vue的Virtual Dom实现snabbdom解密
2017/05/03 Javascript
详解vue-cli 脚手架项目-package.json
2017/07/04 Javascript
详细分析单线程JS执行问题
2017/11/22 Javascript
vue注册组件的几种方式总结
2018/03/08 Javascript
vuex提交state&amp;&amp;实时监听state数据的改变方法
2018/09/16 Javascript
小程序hover-class点击态效果实现
2019/02/26 Javascript
在vue中阻止浏览器后退的实例
2019/11/06 Javascript
vue-cli3中配置alias和打包加hash值操作
2020/09/04 Javascript
[01:07:11]Secret vs Newbee 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[56:13]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第一场 1月10日
2021/03/11 DOTA
Python中的ConfigParser模块使用详解
2015/05/04 Python
让Python更加充分的使用Sqlite3
2017/12/11 Python
DataFrame 将某列数据转为数组的方法
2018/04/13 Python
selenium+python自动化测试之页面元素定位
2019/01/23 Python
pandas.cut具体使用总结
2019/06/24 Python
Python自动化导出zabbix数据并发邮件脚本
2019/08/16 Python
Django 在iframe里跳转顶层url的例子
2019/08/21 Python
Python箱型图处理离群点的例子
2019/12/09 Python
关于Pytorch MaxUnpool2d中size操作方式
2020/01/03 Python
python3.6连接mysql数据库及增删改查操作详解
2020/02/10 Python
Python实现图片查找轮廓、多边形拟合、最小外接矩形代码
2020/07/14 Python
python和C++共享内存传输图像的示例
2020/10/27 Python
html5的画布canvas——画出简单的矩形、三角形实例代码
2013/06/09 HTML / CSS
美国性感内衣店:Yandy
2018/06/12 全球购物
小学教师师德承诺书
2014/05/23 职场文书
员工保密承诺书
2014/05/28 职场文书
2014年依法行政工作总结
2014/11/19 职场文书
2014年医院党建工作总结
2014/12/20 职场文书
自我评价优缺点范文
2015/03/11 职场文书
2016年大学自主招生自荐信范文
2015/03/24 职场文书
《曹冲称象》教学反思
2016/02/20 职场文书