最近,测试人员提出了一个bug,仔细看了之后,发现是前任开发者留下的,而且还是未完成的项目。测试人员说“搜索条件与内容没有关联”,带着疑问的我看了一下项目,发现了。。。额。。。其实是没有开发完成,需要添加功能。MD (# ̄~ ̄#)
好,带着疑问我就去找问题了,现在打开页面,通过搜索关键字,在IDEA中定位到了页面,仔细一看页面代码,我擦,混乱的一批,先看看下面jsp里面的一部分代码,是这样的:
A.jsp:
<span class="l"> <a title="新增" href="javascript:;" :visible="@baseFuncInfo.authorityTag('EquipMent#Add')" ms-click="@repairObj.openEditForm(null,{pktypeid:''})" class="btn btn-primary radius "><i class="Hui-iconfont"></i> 新增</a> <a title="编辑" href="javascript:;" :visible="@baseFuncInfo.authorityTag('EquipMent#Edit')" ms-click="openEditForm1()"<%-- ms-click="repairObj.openEditForm(el.id)" --%>class="btn btn-primary radius ml-10" ><i class="Hui-iconfont"></i>编辑</a> <a title="删除" href="javascript:;" :visible="@baseFuncInfo.authorityTag('EquipMent#Del')" ms-click="delOne()" class="btn btn-danger radius ml-10" ><i class="Hui-iconfont"></i>删除</a> </span>
嗯嗯,没错,这是使用了貌似很高级的avalon技术。现在我想看看添加的逻辑代码是怎样的,没错,就是这一段ms-click="@repairObj.openEditForm(null,{pktypeid:''})"
,很自然的回去找对应的js代码,先打开A.js文件,然后找到repairObj
对象,在去找openEditForm
,很清晰的思路,想想也高兴。然鹅,事实并非这样,repairObj
里面没有openEditForm
这个方法,代码是这样的o(╥﹏╥)o:
var EquipMent = avalon.define({ //识别ID $id: "xxxx", repairObj: new ListBody( { modelName: "/aaa", modelCN: "ceshi", w: 800, h: 600, jspModelName: "system", queryCB: function (res) { if(res.bizData.list != null){ EquipMent.list.clear(); EquipMent.list = res.bizData.list; } EquipMent.jQobj.afterQuery(); setScroll("list9"); }, editModName: "xxxx", searchHtmlBody: { id: "", typeid: "", }, searchDoBody: { id: "", typeid: "", } }),
Ctrl+F 找啊找啊找,一直找不到,然鹅,我发现了原来这个js类有引入其它的js文件,没错就是modes.js
MD,太坑了吧,modes.js
里面,其实有个ListBody
方法,所以repairObj
才new得如此的放纵。
这里引发的思考:
当一个js(这里叫A.js)引入了另外一个js(这里叫B.js),A.js可以完全使用B.js里面的代码。
包括里面的方法对象等等。。。。。
而这个B.js可以封装公用的东西,如共同的访问地址,共同的对话框and so on…
而A.js可以new B.js里面的方法,通过传参的方式来设置到B.js里面。
当然项目中这样使用是最好的,如modes.js
里面的部分代码:
function ListBody(opt){ this.checkedName=opt.checkedState!=undefined?opt.checkedState:"checkedState";//选中的属性名 this.allCheckBox=opt.allCheckBox!=undefined?opt.allCheckBox:false;//全选按钮状态 this.sysParam=sysParamDic; this.list=[];//列表 this.hideorshow=opt.hideorshow!=undefined?opt.hideorshow:true; this.basePageInfo=basePageInfo();//基本分页码 this.paginationInfo=buildPageInfo(this.hideorshow);//基本分页 this.parentData={};//上级页面传递的数据 this.editModName=opt.editModName?opt.editModName:""; this.modelName=opt.modelName?opt.modelName:"";//模块名称 this.modelCN=opt.modelCN?opt.modelCN:"";//模块的中文名 this.jspModelName=opt.jspModelName?opt.jspModelName:""; this.queryCB=opt.queryCB||function(){}; this.w=opt.w||900; this.h=opt.h||700; //共同的url this.urls={ "list":getRootPath()+"/"+this.modelName+"/"+"list.do", "delall":getRootPath()+"/"+this.modelName+"/"+"delall.do", "del":getRootPath()+"/"+this.modelName+"/"+"del.do", "edit":getRootPath()+"/"+this.jspModelName+"/"+this.modelName+"edit", }; //查询预设体(要在界面上显示的) this.searchHtmlBody={ }; //查询实际体(缓存体) this.searchDoBody={ pageNum:0, pageSize:0, }; this.searchHtmlBody=opt.searchHtmlBody?opt.searchHtmlBody:{};
但是modes.js
也有不好之处,顺便吐槽下,就是【引入的类】强制子类去按照它的约束来命名,例如:A.jsp
里面的部分代码:
<div class="row cl"> <label class="form-label col-xs-4 col-sm-2" style="text-align: right;"> <span class="c-red">*</span>名称: </label> <div class="formControls col-xs-8 col-sm-9"> <input type="text" name="f1cqmc" placeholder="" class="input-text" required="true" ms-duplex="@Body.subRecode.devicename"> </div> </div>
上面的@Body.subRecode.devicename
,其实就是avalon的双向绑定,一般我们会这样去思考,先找到Body,很容易的我们会在A.js
里面找到了avalon定义的Body
:
然后再找subRecode
,其实,在A.js
里面是找不到的,因为它已经复制给modes.js
里的EditBody
了,要去modes.js
里面找,而A.js
里面的Body里的recode方法
已经赋值给了modes.js
的subRecode
,简单的说,就是把责任全交给了subRecode
并充当了搬运工。
哎…一开始看着项目都头痛,代码全都跳到了引入类里去处理了,具体的实现也不一目了然。
现在好多了,能把代码弄懂了,会看整个项目,其实里面有封装的思维是很好的,但是也体现了很多的缺点,比如:
- “移植性”比较差,换了其它的模块就不能使用了
- “耦合性高”,调用者必须按调用对方js来命名
- “可读性差”,没有把注释写好,很多命名都不清晰
最后,还是要感谢一下外包的人员的,因为这次的代码,让我有了思考的动力,让我对这个项目有了更深刻的理解了,O(∩_∩)O哈哈~。