浅谈:javascript的面向对象编程之具体实现
下面的javascript代码都是需要使用jQuery插件来做的。希望大家可以搭建好工作环境
首先我们来做一个练习:在一个删除的超链接中添加一个提示信息,提示是否确认删除。
一般情况下我们都会这么做
<html> <head> <title>delete.html</title> </head> <script type="text/javascript"> function deleteTest(){ window.confirm("是否确认删除"); } </script> <body> This is my HTML page. <br> </body> <!-- 给a的超链接添加一个点击事件 --> <a onclick="deleteTest()" href="">删除</a> </html>
但是如果现在整个项目中,有100个删除的超链接,如果按照上面的方法,岂不是要写100个onclick=deleteTest(),会累死人的
能不能写一个方法delete方法,然后每次在页面上调用即可。答案是可以的
具体的代码和分析如下
delete.html的代码
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 2 <html> 3 <head> 4 <title>delete2.html</title> 5 6 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 7 <meta http-equiv="description" content="this is my page"> 8 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 9 10 <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> 11 12 </head> 13 <!-- 导入jQuery和自定义插件,jQuery的插件大家自己去下载 --> 14 <script type="text/javascript" src="../js/jquery-1.4.2.js"></script> 15 <script type="text/javascript" src="../js/js_delete.js"></script> 16 <body> 17 <!-- 可以测试一些,每个删除的超链接都有了提示方法 --> 18 <a href="">删除</a><br/> 19 <a href="">删除</a><br/> 20 <a href="">删除</a><br/> 21 <a href="">删除</a><br/> 22 23 </body> 24 </html>
js_delete.js的代码如下
1 /** 2 * 既然是希望所有的页面都可以使用删除提示,那我们干脆做一个jQuery的插件 3 * 在引入jQuery的同时,引入我们自己的js文件,这样页面就可以使用了 4 * 这里我们使用的全局方法来定义 5 * 6 * 说明: 7 * 1、在jQuery插件中,使用的是带参数的json格式的参数,这样可以降低耦合性, 8 * 当然你也可以直接写$(this).text()=="删除" 但是这样耦合性较高 9 * 2、this 10 * 这里的this指的是a标签对象 11 * 3、为什么先要给a标签unbind("click")(解除click绑定),然后在绑定点击事件 12 * 原因:首先我们不确定a标签是否有其他绑定事件,因为多个事件的叠加或造成错误 13 * 这样写的会避免一些不必要的麻烦。 14 * $(this).bind("click",function(){ 15 点击时候发生的事件都可以子啊这个函数里面写 16 }); 17 */ 18 (function(jQuery){//形参是jQury 19 $.deleteTest = function(json){//自定义jquery的插件,参数是使用带有json的参数 20 $("a").each(function(){//获取指定页面面上所有的超链接标签(a) 21 if($(this).text()==json.condision){//判断的条件 22 $(this).unbind("click");//首先给删除超链接去除点击时间 23 $(this).bind("click",function(){//给删除超链接添加点击时间 24 return window.confirm(json.message);//显示判断框 25 }); 26 } 27 }); 28 }; 29 30 })(jQuery);//实参也是jQuery 31 32 $().ready(function(){//在页面加载完成以后立刻执行 33 $.deleteTest({//传递json格式的参数 34 condision:"删除",//传入执行的条件 35 message:"您确定要删除吗?"//传入提示信息 36 }); 37 //只要把这个js导入相应的页面,那么就可以对任何删除的超链接进行提示 38 });
通过上面的例子我们可以发现,我们可以通过制作jQuery插件的方法,来对页面上的元素进行操作,而不需要在页面上写onclick=""
真正的javascript架构,在页面上是很少可以看到js代码的。js代码一般都封装在js文件里面。
下面再来做一个练习:
写一个全选的方法,让他在这个项目中,对所有引入该js的页面都有效
详细的代码和分析如下:
selectAll.html代码如下
1 <html> 2 <head> 3 <title>selectAll.html</title> 4 <script type="text/javascript" src="../js/jquery-1.4.2.js"></script> 5 <!-- 只要导入这个js文件,所有的全选对应名字,就可以拥有全选功能了 6 --> 7 <script type="text/javascript" src="../js/js_selectAll.js"></script> 8 <body> 9 <input name="selectAll" type="checkbox"/>全选<br/> 10 11 <input name="demoCheckboxs" type="checkbox"/>java<br/> 12 <input name="demoCheckboxs" type="checkbox"/>php<br/> 13 <input name="demoCheckboxs" type="checkbox"/>c++<br/> 14 <input name="demoCheckboxs" type="checkbox"/>.net<br/> 15 <input name="demoCheckboxs" type="checkbox"/>c<br/> 16 </body> 17 </html>
js_selectAll.js代码如下
1 /* 2 * 首先我们分析一下:全选是针对某个对象的,在某个对象有个全选按钮,点击按钮 3 * 把下面的复选框都设置成为被选中,所有制作jQuery插件应该是一个原型方法 4 */ 5 6 (function(jQuery){ 7 $.fn.selectAll=function(checkboxName){ 8 //谁调用此函数,this代表谁 9 if($(this).attr("checked")){//判断全选按钮是不是被选中, 10 //如果被选中,把名称为checkboxName的复选框全部选中 11 $("input[name='"+checkboxName+"']").attr("checked",true); 12 }else{ 13 //如果没有被选中,把名称为checkboxName的复选框全部不选中 14 $("input[name='"+checkboxName+"']").attr("checked",false); 15 } 16 }; 17 })(jQuery); 18 19 20 $().ready(function(){ 21 //给全选按钮添加点击事件 22 $("input[name='selectAll']").unbind("click"); 23 $("input[name='selectAll']").bind("click",function(){ 24 $(this).selectAll("demoCheckboxs");//传入需要被全选的复选框的name属性 25 }); 26 });
通过上面两个练习,我们可以得出,在写js代码的时候,一定要考虑重用性。不能看到一个功能,就直接onclick什么的,那样代码的复用率极低,也不利于后期的维护
下面进入我们js的面向对象的编程介绍
我们下面的案例使用了jQuery的一个插件zTree ,如果希望看懂全部代码,需要学习zTree的知识,如果仅仅需要看懂思想,只有看懂架构即可
需求:有一个权限树,管理员,在为用户添加权限,点击设置权限,下面显示隐藏div和用户名。异步查询数据库里面的用户权限,如果拥有全部权限,把全选按钮选中
点击权限按钮可以全选所有权限。点击保存,向服务器发送请求,保存数据到数据库。还可以设置用户的权限,添加或者修改。全程使用无刷新的方式进行操作!(使用ajax异步的方式发送请求)
页面示例:
共总有如下权限:
点击设置权限按钮
显示在下面隐藏的div、用户名,权限树等信息
想一想这个应该怎么去做:
如果使用以前js函数的写法,感觉就是一个很累而且工厂量很大的事情,我们可以使用面向对象的方法来思考问题
我们把点击设置权限以后的操作分为:初始化(包含初始化事件、初始化数据),对象的操作行为、数据保存等
首先我们给出页面jsp代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ include file="/WEB-INF/jsp/comm/common.jsp"%> <script language="javascript" src="${pageContext.request.contextPath}/js/user-list.js"></script> <script language="javascript" src="${pageContext.request.contextPath}/js/jquery-checkbox.js"></script> <script language="javascript" src="${pageContext.request.contextPath}/js/jquery-ztree-2.5.js"></script> <script language="javascript" src="${pageContext.request.contextPath}/js/privilege_practice2.js"></script> <link rel="stylesheet" type="text/css" href="zTreeStyle/zTreeStyle.css"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户列表</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <div id="Title_bar"> <div id="Title_bar_Head"> <div id="Title_Head"></div> <div id="Title"><!--页面标题--> <img border="0" width="13" height="13" src="${pageContext.request.contextPath }/css/images/title_arrow.gif"/> 用户管理 </div> <div id="Title_End"></div> </div> </div> <div id="MainArea"> <table cellspacing="0" cellpadding="0" class="TableStyle"> <!-- 表头--> <thead> <tr align=center valign=middle id=TableTitle> <td width="100">用户名</td> <td width="100">所属部门</td> <td>职位</td> <td>相关操作</td> </tr> </thead> <!--显示数据列表--> <tbody id="TableData" class="dataContainer" datakey="userList"> <s:iterator> <tr class="TableDetail1 template"> <td><s:property value="username"/></td> <s:hidden name="uid"></s:hidden> <td><s:property value="department.dname"/></td> <td> <s:iterator value="posts"> <s:property value="pname"/> </s:iterator> </td> <td><a onClick="return delConfirm()" href="list.html">删除</a> <a href="saveUI.html">修改</a> <s:a>设置权限</s:a> </td> </tr> </s:iterator> </tbody> </table> <div id="TableTail"> <div id="TableTail_inside"> <a href="userAction_addUI.action"><img src="${pageContext.request.contextPath }/css/images/createNew.png" /></a> </div> </div> <div class="ItemBlock_Title1" id="userTitle" style="display: none;"><!-- 信息说明 --><div class="ItemBlock_Title1"> <img border="0" width="4" height="7" src="${pageContext.request.contextPath }/css/blue/images/item_point.gif"/> <div id="userImage"></div> </div> <div class="ItemBlock_Title1" id="privilegeTitle" style="display: none;"><div class="ItemBlock_Title1"> <img border="0" width="4" height="7" src="${pageContext.request.contextPath }/css/blue/images/item_point.gif" />选择权限</div> </div> <!-- 表单内容显示 --> <div class="ItemBlockBorder" style="display: none;" id="privilegeContent"> <div class="ItemBlock"> <table cellpadding="0" cellspacing="0" class="mainForm"> <!--表头--> <thead> <tr align="LEFT" valign="MIDDLE" id="TableTitle"> <td width="300px" style="padding-left: 7px;"> <!-- 如果把全选元素的id指定为selectAll,并且有函数selectAll(),就会有错。因为有一种用法:可以直接用id引用元素 --> <input type="checkbox" id="allchecked" /> <label for="cbSelectAll">全选</label> </td> </tr> </thead> <!--显示数据列表--> <tbody id="TableData"> <tr class="TableDetail1"> <!-- 显示权限树 --> <td> <ul id='privilegeTree' class="tree"> </td> </tr> </tbody> </table> </div> </div> <!-- 表单操作 --> <div id="InputDetailBar"> <image id="savePrivilege" src="${pageContext.request.contextPath }/css/images/save.png"/> </div> </div> </body> </html>
给出js的框架代码(只有框架,没有具体实现):下面代码就是使用js面向对象编程,把所有的定义都放在privilege对象中
最后只需要调用privilege.init.initEvent();即可完成对内容的实现
1 var privilege ={ 2 /** 3 * 初始化的东西全部在init里面完成 4 */ 5 init:{ 6 7 /** 8 * 初始化事件,所有的初始化事件都在initEvent完成 9 */ 10 initEvent:function(){ 11 12 }, 13 14 /** 15 * 初始化数据,对数据的初始化操作全部在initData完成 16 */ 17 initData:function(){ 18 19 }, 20 21 22 }, 23 24 25 /** 26 * 所有功能的操作都是在这里面完成 27 */ 28 pFunction:{ 29 30 /** 31 * 所有和权限树有关的操作都在privilegeTree里面完成 32 */ 33 privilegeTree:{ 34 35 /** 36 * loadPrivilegeTree:完成对权限树的加载 37 */ 38 loadPrivilegeTree:function(){ 39 40 }, 41 42 43 /** 44 * controlCheckBox:完成对树规则控制 45 */ 46 controlCheckBox:function(){ 47 48 }, 49 50 51 /** 52 * checkAll:完成对树的全选操作 53 */ 54 checkAll:function(){ 55 56 }, 57 58 /** 59 * savePrivilege:完成对树权限的保存 60 */ 61 savePrivilege:function(){ 62 63 } 64 }, 65 66 /** 67 * userOption:完成所有的用户功能的实现 68 */ 69 userOption:{ 70 /** 71 * 显示用户名的操作 72 */ 73 showUsername:function(){ 74 75 } 76 }, 77 78 /** 79 * divOption:对div的所有操作 80 */ 81 divOption:{ 82 /** 83 * 显示div的所有操作 84 */ 85 showDiv:function(){ 86 87 } 88 } 89 90 }, 91 92 data:{ 93 94 } 95 };
$().ready(function(){
privilege.init.initEvent();
});
对上面代码的部分实现:
1 var privilege ={ 2 /** 3 * 初始化的东西全部在init里面完成 4 */ 5 init:{ 6 7 /** 8 * 初始化事件,所有的初始化事件都在initEvent完成 9 */ 10 initEvent:function(){ 11 //点击设置权限按钮的事件 12 $("a").each(function(){ 13 if($(this).text()=="设置权限"){ 14 $(this).unbind("click"); 15 $(this).bind("click",function(){ 16 /** 17 * 在点击设置权限的时候,首先要初始化数据 18 * 1、显示div 19 * 2、显示用户名 20 * 3、加载权限树 21 * 22 * 说明:使用nitData.call(param),可以把 23 * initData的这个函数的调用者设置为param 24 * 25 * 在这里进行调用,然后在在每个具体的方法里面进行实现, 26 * 做到了面向对象的变成,这是javascript面向对象的核心 27 */ 28 29 privilege.init.initData.call(this); 30 privilege.pFunction.divOption.showDiv(); 31 privilege.pFunction.userOption.showUsername(); 32 privilege.pFunction.privilegeTree.loadPrivilegeTree(); 33 return false; 34 }); 35 } 36 }); 37 38 39 /** 40 * 全选按钮事件 41 */ 42 $("#allchecked").unbind("click"); 43 $("#allchecked").bind("click",function(){ 44 privilege.pFunction.privilegeTree.checkAll(); 45 }); 46 47 /** 48 * 保存权限事件 49 */ 50 $("#savePrivilege").unbind("click"); 51 $("#savePrivilege").bind("click",function(){ 52 privilege.pFunction.privilegeTree.savePrivilege(); 53 }); 54 55 }, 56 57 /** 58 * 初始化数据,对数据的初始化操作全部在initData完成 59 */ 60 initData:function(){ 61 /* 62 * 使用jQuery赋值 63 * $(this).parent().siblings("td:first").text() 64 * 表示调用该方法的节点的父节点的兄弟节点中第一个的文本值 65 * 也就是<td><s:property value="username"/></td> 66 * $(this).parent().siblings("input[type='hidden']:first").val(); 67 * 表示:调用此方法的节点的父节点的兄弟节点类型为input type=hidden的第一个的值 68 * 也就是 <s:hidden name="uid"></s:hidden> 69 * 70 * 下面是具体的jsp页面的对应值 71 * <s:iterator> 72 <tr class="TableDetail1 template"> 73 <td><s:property value="username"/></td> 74 <s:hidden name="uid"></s:hidden> 75 <td><s:property value="department.dname"/></td> 76 <td> 77 <s:iterator value="posts"> 78 <s:property value="pname"/> 79 </s:iterator> 80 </td> 81 <td><a onClick="return delConfirm()" href="list.html">删除</a> 82 <a href="saveUI.html">修改</a> 83 <s:a>设置权限</s:a> 84 </td> 85 </tr> 86 </s:iterator> 87 */ 88 var username = $(this).parent().siblings("td:first").text(); 89 var uid = $(this).parent().siblings("input[type='hidden']:first").val(); 90 //给data数据中数据赋值 91 privilege.data.user.uid = uid; 92 privilege.data.user.username=username; 93 94 }, 95 96 97 }, 98 99 100 /** 101 * 所有功能的操作都是在这里面完成 102 */ 103 pFunction:{ 104 105 /** 106 * 所有和权限树有关的操作都在privilegeTree里面完成 107 */ 108 privilegeTree:{ 109 110 /** 111 * loadPrivilegeTree:完成对的加载 112 */ 113 loadPrivilegeTree:function(){ 114 115 }, 116 117 118 /** 119 * controlCheckBox:完成对树规则控制 120 */ 121 controlCheckBox:function(){ 122 123 }, 124 125 126 /** 127 * checkAll:完成对树的全选操作 128 */ 129 checkAll:function(){ 130 131 }, 132 133 /** 134 * savePrivilege:完成对树权限的保存 135 */ 136 savePrivilege:function(){ 137 138 } 139 }, 140 141 /** 142 * userOption:完成所有的用户功能的实现 143 */ 144 userOption:{ 145 /** 146 * 显示用户名的操作 147 */ 148 showUsername:function(){ 149 $("#userImage").text(privilege.data.user.username); 150 } 151 }, 152 153 /** 154 * divOption:对div的所有操作 155 */ 156 divOption:{ 157 /** 158 * 显示div的所有操作 159 */ 160 showDiv:function(){ 161 $("#userTitle").show(); 162 $("#privilegeTitle").show(); 163 $("#privilegeContent").show(); 164 } 165 } 166 167 }, 168 169 170 /** 171 * 所有需要的数据都可以在这里面进行定义 172 */ 173 data:{ 174 user:{//user数据 175 uid:'', 176 username:'' 177 } 178 } 179 }; 180 181 $().ready(function(){ 182 privilege.init.initEvent(); 183 });
如果是了解一下思想,看到这里就可以了,下面的代码需要jQuery的ZTree知识。
上述代码的全部实现:说明: $.post()由服务器调用,是异步的,也就是说,想使用$.post()里面的数据,必须保证他被服务器调用已经完成
var privilege ={ /** * 所有初始化的操作 */ init:{ /** * 所有初始化的事件 */ initEvent:function(){ //设置权限的click事件 $("a").each(function(){ if($(this).text()=="设置权限"){ $(this).unbind("click"); $(this).bind("click",function(){ /** * 1、显示所有div * 2、动态显示用户名 * 3、加载动态权限树 */ var hobj = this; //privilege.init.initData(hobj); //设置initData()方法的调用对象就是this,这样就不用传递参数了 privilege.init.initData.call(this); privilege.pFunction.divOption.showDiv();//显示所有的div privilege.pFunction.userOption.showUsername();//动态显示用户名 privilege.pFunction.privilegeTree.loadPrivilegeTree();//加载权限树 //判断全选按钮是否需要全选不能在这,因为在这树还不确定是否已经加载 return false; }); } }); /** * 全选按钮事件 */ $("#allchecked").unbind("click"); $("#allchecked").bind("click",function(){ privilege.pFunction.privilegeTree.checkAll(); }); /** * 保存权限事件 */ $("#savePrivilege").unbind("click"); $("#savePrivilege").bind("click",function(){ privilege.pFunction.privilegeTree.savePrivilege(); }); }, /** * 所有初始化的数据 */ initData:function(){ //alert($(hobj).parent().siblings("td:first").text()); //alert($(hobj).parent().siblings("input[type='hidden']:first").val()); var username = $(this).parent().siblings("td:first").text(); var uid = $(this).parent().siblings("input[type='hidden']:first").val(); privilege.data.user.uid=uid; privilege.data.user.username=username; } }, /** * 按照功能区域的划分 */ pFunction:{ privilegeTree:{//对所有权限树的操作 zTree:'', setting: { isSimpleData: true, treeNodeKey: "mid", treeNodeParentKey: "pid", showLine: true, root: { isRoot: true, nodes: [] }, checkable: true, //设置点击规则 checkType:{ "Y":"p", "N":"s" }, callback:{ beforeChange:function(treeId, treeNode){//在点击树的复选框之前触发 //在点击树的复选框之前,改变规则 privilege.pFunction.privilegeTree.controlCheckBox({ "Y":"p", "N":"s" }); }, /** * 节点点击的时候触发,如果已经全选了,那就把全选按钮选中,否则全选按钮不选中 * @param treeId * @param treeNode */ change:function(treeId, treeNode){ if(privilege.pFunction.privilegeTree.zTree.getCheckedNodes(false).length!=0){//如果没有全部选中 $("#allchecked").attr("checked", false); }else{ $("#allchecked").attr("checked", true); } } } }, /** * 显示权限树 */ loadPrivilegeTree:function(){ var params={ uid:privilege.data.user.uid }; $.post("privilegeAction_showPrivilegesByUid",params,function(data){ alert(data); privilege.pFunction.privilegeTree.zTree=$("#privilegeTree").zTree(privilege.pFunction.privilegeTree.setting,data.privilegeList); /** * 全选按钮是否被选中要在点击设置权限之后显示出来, * 但是又需要在树加载之后,所有这里是判断全选按钮是否选中的最佳位置 */ if(privilege.pFunction.privilegeTree.zTree.getCheckedNodes(false).length!=0){//如果没有全部选中 $("#allchecked").attr("checked", false); }else{ $("#allchecked").attr("checked", true); } }); }, /** * 对权限树复选框的控制 */ controlCheckBox:function(checkType){//设置setting的属性 //获取当前树的setting var setting = privilege.pFunction.privilegeTree.zTree.getSetting(); //前一个setting是属性,后一个数传递的值 setting.checkType = checkType; privilege.pFunction.privilegeTree.zTree.updateSetting(setting); }, /** * 针对某个用户的保存权限 */ savePrivilege:function(){ var checkedNodes = privilege.pFunction.privilegeTree.zTree.getCheckedNodes(true); var mids=""; var length = checkedNodes.length; for(var i=0;i<length;i++){ if(i<length-1){ mids = mids+checkedNodes[i].mid+","; }else{ mids = mids+checkedNodes[i].mid; } } var params={ uid:privilege.data.user.uid, mids:mids, aa:[1,2,3] }; $.post("privilegeAction_savePrivilege.action",params,function(data){ //alert(data); }); }, /** * 全选复选框的实现 */ checkAll:function(){ /** * 在点击全选的时候,设置下新的规则,让全选公共可以实现 * 为什么可以设置,因为只有当树加载出来的时候,你才会进行全选,所以,可以保证树加载 */ privilege.pFunction.privilegeTree.controlCheckBox({ "Y":"ps", "N":"ps" }); if($("#allchecked").attr("checked")){ privilege.pFunction.privilegeTree.zTree.checkAllNodes(true); }else{ privilege.pFunction.privilegeTree.zTree.checkAllNodes(false); } } }, //用户的所有操作 userOption:{ /** * 动态显示用户名,把用户名显示到div中 */ showUsername:function(){ $("#userImage").text(privilege.data.user.username); } }, //div的操作 divOption:{ /** * 显示所有的div */ showDiv:function(){ //把隐藏域变成显示 $("#userTitle").show(); $("#privilegeTitle").show(); $("#privilegeContent").show(); } } }, /** * json对象的数据封装 */ data:{ user:{//封装user数据 uid:'', username:'' } } }; $().ready(function(){ privilege.init.initEvent(); });
总结:javascript面向对象的编程就是把一个大的问题分解,在一个方法里面调用各个方法,在下面各个方法里面进行实现,全程都在一个对象privilege里面
这里只是学一下思想,如果要理解全部的代码,还需要jQuery的zTree知识。
以上就是javascript面向对象编程的思想,希望对大家有用