easyui项目问题集合
1、级联问题(combobox)
combobox至多可以保存2个东西value和text,但我需要第三个数的时候,怎么办?比如,省、市、区的三级级联,我选择市的时候,需要市id,市name,区号,邮编4个数据。这应该怎么办?
我的解决思路:在保存value的时候保存为一个键值对:{id:123,zip:'2344545',Areacode:'45567'},如此选中一个时,获取其value,将其转化为对象,然后一一赋值给相应的隐藏域。
1 /**省-市-区县级联菜单 2 *province(省):provinceName(省名) 3 4 *city(市有邮编和区号,选择市可以级联邮编和区号):根据省得出,cityName(市名)、cityid(市id),zipCode(邮编),areaCode(区号) 5 6 *district(区县有邮编,选择区县可以级联邮编):根据市得出,districtName(区县名)、districtid(区县id),zipCode(邮编) 7 8 */ 9 area:function(){ 10 var arry = this.config.linkage?this.config.linkage:['province','city','district']; 11 var provinceID = arry[0] 12 var cityID = arry[1]; 13 var districtID = arry[2]; 14 var province = $('#'+provinceID).combobox({ 15 url:'/org/address.do?type=province', 16 valueField:'id', 17 textField:'provinceName', 18 onClick:function(record){ 19 var id = record.id; 20 var provinceName = record.provinceName; 21 $('#provinceName').val(provinceName); 22 if(id){ 23 $.get('/org/address.do',{type:cityID,id:id},function(data){ 24 var cityRows = []; 25 for(var i = 0;i<data.length;i++){ 26 var cityName = data[i].cityName; 27 var idZipAreacode = { 28 id:data[i].id, 29 zip:data[i].zipCode, 30 Areacode:data[i].areaCode 31 }; 32 idZipAreacode = JSON.stringify(idZipAreacode); 33 var row = { 34 idZipAreacode:idZipAreacode, 35 cityName:cityName 36 }; 37 cityRows.push(row); 38 } 39 city.combobox("clear").combobox('loadData',cityRows); 40 district.combobox("clear"); 41 $('#cityName').val(''); 42 $('#cityid').val(''); 43 $('#districtName').val(''); 44 $('#districtid').val(''); 45 $('#zipCode').textbox("clear"); 46 $('#areaCode').textbox("clear"); 47 },'json'); 48 } 49 } 50 }); 51 var city = $('#'+cityID).combobox({ 52 valueField:'idZipAreacode', 53 textField:'cityName', 54 onClick:function(record){ 55 var data = record.idZipAreacode; 56 if(data){ 57 var cityName = record.cityName; 58 $('#cityName').val(cityName); 59 data = JSON.parse(data); 60 $('#cityid').val(data.id); 61 $('#zipCode').textbox("setValue",data.zip); 62 $('#areaCode').textbox("setValue",data.Areacode); 63 $.get('/org/address.do',{type:districtID,id:data.id},function(data){ 64 var districtRows = []; 65 for(var i = 0;i<data.length;i++){ 66 var districtName = data[i].districtName; 67 var idZipAreacode = { 68 id:data[i].id, 69 zip:data[i].zipCode 70 }; 71 idZipAreacode = JSON.stringify(idZipAreacode); 72 var row = { 73 idZipAreacode:idZipAreacode, 74 districtName:districtName 75 }; 76 districtRows.push(row); 77 } 78 district.combobox("clear").combobox('loadData',districtRows); 79 $('#areaCode').textbox("clear"); 80 $('#districtName').val(''); 81 $('#districtid').val(''); 82 },'json'); 83 } 84 } 85 }); 86 var district = $('#'+districtID).combobox({ 87 valueField:'idZipAreacode', 88 textField:'districtName', 89 onClick:function(record){ 90 var data = record.idZipAreacode; 91 if(data){ 92 var districtName = record.districtName; 93 $('#districtName').val(districtName); 94 data = JSON.parse(data); 95 $('#districtid').val(data.id); 96 $('#zipCode').textbox("clear").textbox("setValue",data.zip); 97 } 98 99 } 100 }); 101 } 102 这里我将其封装在Linkage中,引用时只要在页面上先实例化一下,然后调用即可。例:var linkage = new Linkage();linkage.area()
但这里在编辑页面上会出现一个问题,问题描述:在添加页面我选择了浙江省-金华市-永康市,如图 所以在编辑页面上必须一开始就有浙江省下所有的市,金华市下的所有区。问题来了,市区都是根据前面一个级联出来的,编辑页面刚刚加载时没有做过级联啊(级联只会在值发生onClick的时候才会发生,上面的代码可以看到)。那么市只有一个“金华市”,区只有一个“永康市”。看了许多遍api发现“data-option=‘url:.....’”可以用,页面一加载时根据前面的一个id先做一遍查询。但是问题又有了:我需要的value是许多值得集合,那几说明我的数据要进行转化。然后又刷了好几遍api,发现loadFilter可以用。因为级联是项目开始的时候就做的,不熟悉所以都后来就打了许多的补丁(例如上面的代码,功能都能实现但不是最优的。因为没有发现loadFilter的作用啊。。。。)。
用loadFilter的代码我就不粘了,大家可以自己写写看。当然这是我想的方法,可能还有更简单的。如何有的话,大神们也可以一起探讨一下,让我学习学习。
但是遗留下来一个问题:做级联其中最好是用combobox的onChange事件,因为其只有在值进行改变时候才触发,这样用户体验更好,不会说点了一模一样的值也去级联了。但我用的是onclick为什么呢,就是在导入的时候发生一个严重的错误。我写的项目也许多这样的功能:比如添加一条信息时,我将选择一条信息进行导入,里面有省市区可以级联。如果用onChange写时,由于由空变成有值,触发了级联将原来的值覆盖了。不得已只能用onClick替换了。
这是我做级联是遇到的问题及解决方式和一个遗留的问题,为自己记录一下以希冀以后能够解决。如果大神们有什么解决方式的话,请不吝赐教。
2、返回功能问题
大家在做返回功能的时候都遇到了什么问题,可以一起讨论一下互相吸取一下经验。返回功能在项目应该算是一个比较普通常用的功能,但想做好我还是遇到了许多问题,即使在我记录这个问题的时候也只是解决了一些问题而不是最优的方式。首先描述一下我要设计的返回功能:返回,1、首先是在跳转到二级页面后可以返回到上一级页面;2、其次是在搜索过之后跳转的返回需要保留其搜索条件及数据;3、再其次是当选中一行点击编辑或者查看返回时还是需要选中这一行。
本来我很单蠢的用了go(-1)或者back(),你想:返回上一级页面时不刷新,然后返回页面进行局部刷新,这样除了记录行这个功能不行以外其他都可以。当时我还是沾沾自喜的,然而一个一个页面进行测试时时没有问题的,但是在打开多个页面的二级页面然后按返回时就哭笑不得了,它将之前一个个所以的页面都返回了.....。这个问题但是让我纠结了许久。
解决思路:go(-1)不可以用,用url直接跳转(只是返回功能所要3个功能只实现了返回上一级这个功能)。因为我用的是easyui的tab做的显示页面。
1 /** 2 * 返回 3 */ 4 var FormOpr= function(config){ 5 this.config=config; 6 7 }; 8 FormOpr.prototype = {//封装在项目里用的还是比较多的 9 back:function(e){ 10 var tab = parent.$('#tabs-list').tabs('getSelected');//获取当前选中的tab 11 var url = tab.find('iframe').attr('src');//获取url 12 window.location.href = url; 13 } 14 }; 15 16 //页面引用 17 var form = new FormOpr(); 18 form.back();
虽然是可以跳转了也不出错,问题是:一跳转就刷新,查询条件不能保存更别说行记录了。网上有一些方法,如保存到session里传到后台里等等。但今天我要说的是 window.localStorage。localStorage一些注意点,看一下这个还是有些帮助的http://www.jb51.net/article/78013.htm(这个百度的个人觉得易懂所以放在这里,如果原作者觉得侵害了您的权益,联系我会立马删掉的)。
解决思路:用window.localStorage将查询条件和行索引记录到缓存里,然后使用。因为代码有些复杂所以用图片了。(如图一至图五),所有共用的js我都进行封装了
图一:如果存在缓存时,将查询条件注入到查询form中,并且作为默认查询条件传到后台
图二:当查询成功后,获取行记录,选中相应行
图三:设置点击行索引缓存,获取行索引缓存、或查询条件缓存
图四:设置查询条件缓存
图五:设置行索引缓存,查看页面与编辑页面差不多
如此就可以实现上所说的返回功能了,实现功能返回后如图六
但如果你觉得到此就结束了,那就错了。看过windows.localStorage注意点就知道其是有默认空间大小为5M的。而且如果不做处理的时候,你想缓存一直存在,我页面刷新或者关闭的时候再打开时候不是还有缓存了,那我们一打开就有查询或者点击记录了(在这里我有想到手机app猎豹浏览器如果不设置关闭清空记录,下次打开的时候还是会保留之前浏览的页面不知道是不是可以用localStorage实现的),但这里我们不要保留,所以在关闭tab(清空当前关闭tab的缓存)、刷新页面和关闭页面(清空所有localStorage缓存)。
//tab页面关闭时清空当前页面的缓存 $('#tabs-list').tabs({//当tab标签关闭时,将对应tab的localStorage清除掉 onClose:function(title,index){ var searchKeyName = "searchData_" + index; var gridKeyName = "dataGrid_" + index; window.localStorage.removeItem(searchKeyName); window.localStorage.removeItem(gridKeyName); } }); //关闭或者刷新页面时清空所有缓存 window.onbeforeunload = function(){ window.localStorage.clear(); }
到此功能已经实现,但可能还有更优的方法,如果你知道请不吝指教。而且我对windows.localStorage不是怎么了解,只是看到有人说这个可以做缓存才在网上找了一些资料粗略的了解了一下。可能会引起其他的一下错误,如果有人看出我代码上的错误或者不足,请务必告知我,不胜感激!
以后遇到问题我也会不停记录更新,希望给他人和今后的自己一点积累的经验。
3、datagrid行编辑时getChanges事件问题
我个人认为getChanges还是一个很好用的事件(即使它还有一些问题)。问题:1、获取不到值,看见网上说在使用updaterow修改数据后使用getChanges获取不到数据,这个问题至今项目里没有遇到所以这里先不写解决方法了,之后遇到再添加。2、同一条数据同时存在不同的状态中,bug产生场景:在页面编辑(不是添加)时,提交数据时我分别用了insert、update、delete,但是问题出现了,当对一条数据先编辑,然后再删除时,它同时记录到了update和delete中了,如果后台是先删除,再修改的话会导致后台找不到要修改的数据(因为之前已经删除了),这个问题在前端层面是怎么解决的,私下认为这个是否是getChanges事件的bug了:我已经删除了,为什么还会记录到update中呢?不知道是否我理解错误!
解决思路:之前在网上看见有人说,easyui以及miniui等等框架都有缓存的功能。他会了,而不是我们使用getChanges才进行对比然后获取数据的。因为我最后的操作是删除,而其也记录下我之前修改过的操作了。所以最后的解决方法只能去重了,但update里的某数据在delete中存在则把该数据从update中删除。
1 function getUpdated(updatedRows,deletRows){ 2 //获取正确的update数据:除去delete中的数据 3 var actualupdatedRows = updatedRows; 4 for(var i = 0;i<updatedRows.length;i++){ 5 var index = $.inArray(updatedRows[i],deletRows); 6 if(index !== -1){ 7 actualupdatedRows.splice(index); 8 } 9 } 10 return actualupdatedRows; 11 }
3、tab关闭问题:关闭全部、关闭当前(关闭当前不用多说,获取当前选中的tab的索引关闭即可)、关闭其他、关闭左边、关闭右边
刚刚做这个功能的时候觉得十分简单,思路:获取到所有的tab一个一个关闭就行了。简单,十分简单!然后现实打了我一个嘴巴子。不知道大家怎么知道(反正当时我是不知道的),用close关闭时,每关一个,tab的length都会改变。到最后就会关不全,然后我就百思不得其解,在网上找了一个代码应付了一下:
到现在为止我其实也没有了解这个代码是什么意识,这么就可以用“$('...').tabs('cloase',0)”关闭了了呢,close带的参数不是标题或者索引的吗?虽然我不是怎么懂这个代码,但关闭全部这个代码还是可以实现的,就是“关闭其他”不怎么好用。
到项目开发到后面有一些空余的时间就重新思考了一下,发这个还是很好解决的,既然关闭一个会改变tabs,那么事先保存下来不就行了。我的项目tab的标题必定不会重复,所以我保存下来的是tab的标题。下面是我实现的代码,可以看看,如果有问题可以一起讨论。
1 //首先html页面先建一个menu 2 <div id="rightMouse" class="easyui-menu" style="width:120px;font-size: 14px;letter-spacing: 1px;"> 3 <div id="closeCurrent" data-options="iconCls:'icon-cancel'" >关闭当前</div> 4 <div id="closeAll" name="closeAll">关闭所有</div> 5 <div id="closeLeft" name="closeLeft">关闭左边</div> 6 <div id="closeRight" name="closeRight">关闭右边</div> 7 <div id="closeOther" name="closeOther">关闭其他</div> 8 </div> 9 10 //js代码 11 <script> 12 $('#tabs-list').tabs({//tab右键功能 13 onContextMenu: function(e, title, index){ 14 e.preventDefault();//阻止浏览器默认事件 15 var tabs = $("#tabs-list").tabs("tabs"); 16 var last = tabs.length-1; 17 $('#tabs-list').tabs('select',index); 18 if(title=="首页"){ 19 return false; 20 } 21 if(index==1&&index==last){//如果该tab即是第一个(除首页以外),又是最后一个 22 $('#rightMouse').menu('disableItem', $('#closeAll')[0]);//关闭所有不可用 23 $('#rightMouse').menu('disableItem', $('#closeLeft')[0]);//关闭左边不可用 24 $('#rightMouse').menu('disableItem', $('#closeRight')[0]);//关闭右边不可用 25 $('#rightMouse').menu('disableItem', $('#closeOther')[0]);//关闭其他不可用 26 }else{ 27 $('#rightMouse').menu('enableItem', $('#closeAll')[0]); 28 $('#rightMouse').menu('enableItem', $('#closeOther')[0]); 29 if(index==1){//如果该tab是第一个(除首页以外),但不是最后一个 30 $('#rightMouse').menu('disableItem', $('#closeLeft')[0]);//关闭左边不可用 31 }else{ 32 $('#rightMouse').menu('enableItem', $('#closeLeft')[0]); 33 } 34 if(index==last){ 35 $('#rightMouse').menu('disableItem', $('#closeRight')[0]); 36 }else{ 37 $('#rightMouse').menu('enableItem', $('#closeRight')[0]); 38 } 39 } 40 //显示右键菜单 41 $('#rightMouse').menu('show', { 42 left: e.pageX, 43 top: e.pageY 44 }) ; 45 } 46 }); 47 //获取除首页外所有tabs的title 48 function getTitle(){ 49 var titles = []; 50 //获取所有标签 51 var tabs = $("#tabs-list").tabs("tabs"); 52 var length = tabs.length; 53 for(var i=0;i<length;i++){ 54 var title = tabs[i].panel('options').title; 55 if(title!="首页"){ titles.push(title); } 56 } 57 return titles; 58 } 59 //获取除首页外当前选中左边的tab 60 function getLeftTitle(index){ 61 //获取所有标签 62 var tabs = $("#tabs-list").tabs("tabs"); 63 var length = tabs.length; 64 var titles = []; 65 for(var i=0;i<index;i++){ 66 var title = tabs[i].panel('options').title; 67 if(title!="首页"){ titles.push(title); } 68 } 69 return titles; 70 } 71 //获取除首页外当前选中右边的tab 72 function getRightTitle(index){ 73 //获取所有标签 74 var tabs = $("#tabs-list").tabs("tabs"); 75 var length = tabs.length; 76 var titles = []; 77 var start = index+1; 78 for(var i=start;i<length;i++){ 79 var title = tabs[i].panel('options').title; 80 if(title!="首页"){ titles.push(title); } 81 } 82 return titles; 83 } 84 //关闭当前标签 85 $("#closeCurrent").click(function(){ 86 var tab = $('#tabs-list').tabs('getSelected'); 87 var index = $('#tabs-list').tabs('getTabIndex',tab); 88 $("#tabs-list").tabs("close",index); 89 }); 90 //关闭所有标签 91 $("#closeAll").click(function(){ 92 var titles = getTitle(); 93 for(var i = 0;i<titles.length;i++){ 94 $("#tabs-list").tabs("close",titles[i]); 95 } 96 97 }); 98 //关闭其他标签 99 $("#closeOther").click(function(){ 100 var titles = getTitle(); 101 var tab = $('#tabs-list').tabs('getSelected'); 102 var title = tab.panel('options').title; 103 for(var i = 0;i<titles.length;i++){ 104 if(titles[i] != title){ 105 $("#tabs-list").tabs("close",titles[i]); 106 } 107 } 108 $('#tabs-list').tabs('select',title); 109 }); 110 //关闭选中标签左边的标签 111 $("#closeLeft").click(function(){ 112 var tab = $('#tabs-list').tabs('getSelected'); 113 var index = $('#tabs-list').tabs('getTabIndex',tab); 114 var title = tab.panel('options').title; 115 var titles = getLeftTitle(index); 116 for(var i = 0;i<titles.length;i++){ 117 $("#tabs-list").tabs("close",titles[i]); 118 } 119 $('#tabs-list').tabs('select',title); 120 }); 121 //关闭选中标签右边的标签 122 $("#closeRight").click(function(){ 123 var tab = $('#tabs-list').tabs('getSelected'); 124 var index = $('#tabs-list').tabs('getTabIndex',tab); 125 var title = tab.panel('options').title; 126 var titles = getRightTitle(index); 127 var tab = $('#tabs-list').tabs('getSelected'); 128 var index = $('#tabs-list').tabs('getTabIndex',tab); 129 for(var i = 0;i<titles.length;i++){ 130 $("#tabs-list").tabs("close",titles[i]); 131 } 132 $('#tabs-list').tabs('select',title); 133 }); 134 </script>
这个是我实现的代码,仅供参考。