在自定义grid中,如果一个grid的列很多,窗口无法显示这么长的内容,且我们一般把grid每一行按操作按钮(如编辑删除按钮)放在每一行的最后一列。这时候用户要要操作某一行的数据,如要做“删除”操作时,就要用鼠标拉动水平滚动条,拉动到能看到最后一列的时候再进行点击操作。这就显得比较麻烦了。这时候,右键某一行,把这行最后的按钮内容构造成右键的显示内容,就可以方便地进行操作了。
整体的思路:create一个div,把grid行最后的按钮内容构造成右键的内容,执行最后一行的按钮的onclick事件即可。
主要的代码如下:
/** * 构造grid的右键菜单 * author:liugx */ //orgCellColor存放点击行的原始颜色值 ConRightMenu.orgCellColor = ""; ConRightMenu.clickRow = ""; function ConRightMenu(){ } ConRightMenu.prototype ={ cancelRight:function(){ event.returnValue=false; event.cancelBubble=true; }, getEventElement:function(clickObject){ var evt = Event.getEvent(); return (evt)?(event.target || event.srcElement):clickObject; }, getTrObj:function(){ var oCh = ""; try { if(DOMModel.type()==1){ oCh = conRightMenu.getEventElement().parentElement; }else if(DOMModel.type()==2){ oCh = Event.findElement(evt,"tr"); } }catch(e){ _alert(e.message); return ""; } return oCh; }, changeClassForTD:function(trObj){ //先清空其它的td底色 if(trObj.parentElement){ var allTDObj = trObj.parentElement.getElementsByTagName("TD"); for(var j=0;j<allTDObj.length;j++){ if(allTDObj[j].style.backgroundColor.toUpperCase()=='#DCDCDC'.toUpperCase()){ allTDObj[j].style.backgroundColor = ConRightMenu.orgCellColor; } } } var trChildNodes = trObj.childNodes; //设置tr的底色 for(var i=0;i<trChildNodes.length;i++){ if(i==0){ ConRightMenu.orgCellColor = trChildNodes[i].style.backgroundColor; } trChildNodes[i].style.backgroundColor = '#DCDCDC'; } }, buttonClickFun:function(itemId){ var trObj = $(ConRightMenu.clickRow); if(trObj){ var childNodes = trObj.lastChild.childNodes; for(var i=0;i<childNodes.length;i++){ if(childNodes[i].id == itemId){ childNodes[i].fireEvent("onclick"); } } } }, consButtonHtml:function(trObj){ var result = ""; result += "<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"; var childNodes = trObj.lastChild.childNodes; var childNodesLen = childNodes.length; for(var i=0;i<childNodesLen;i++){ var outerHtml = childNodes[i].outerHTML; var onclickHtml = outerHtml.substring(outerHtml.indexOf("onclick"),outerHtml.length-1); var itemId = childNodes[i].id; result += "<tr onmouseover='this.className=\"mouseOverGrid\";' onmouseout='this.className=\"mouseOutGrid\";'"; result += " onclick='conRightMenu.buttonClickFun(\""+itemId+"\");"; result += "$(\"right_reslut_div\").style.display=\"none\"'><td>"; var tdImg = document.createElement('img'); var tdImgUrl = childNodes(i).currentStyle.backgroundImage.replace("url(\"",""); tdImgUrl = tdImgUrl.replace("\")",""); tdImg.src = tdImgUrl; result += tdImg.outerHTML; result += "</td><td>"+childNodes[i].title+"</td></tr>"; if(i<childNodesLen-1){ result += "<tr><td colspan='2'><div class='rowSplit'></div></td></tr>"; } } result += "</table>"; return result; }, buildRightMenu:function(){ conRightMenu.cancelRight(); var trObj = conRightMenu.getTrObj(); if(trObj){ ConRightMenu.clickRow = trObj.id; var buttonHtml = conRightMenu.consButtonHtml(trObj); if(!$("right_reslut_div")){ var right_res_div = document.createElement('div'); right_res_div.id = "right_reslut_div"; }else{ right_res_div = $("right_reslut_div"); } right_res_div.innerHTML = buttonHtml; right_res_div.style.background = '#DCDCDC'; right_res_div.style.padding = "1 1 1 1"; right_res_div.style.border = "solid #C0C0C0 1px"; right_res_div.style.position = 'absolute'; right_res_div.style.left = event.clientX + geometry.getHorizontalScroll() + 'px'; right_res_div.style.top = event.clientY + geometry.getVerticalScroll() + 'px'; right_res_div.style.width = 100 +'px'; right_res_div.style.height = trObj.lastChild.childNodes.length*18 +'px'; if(!$("right_reslut_div")){ document.body.appendChild(right_res_div); } right_res_div.style.display = ''; conRightMenu.changeClassForTD(trObj); } }, display_right_div:function(){ if($("right_reslut_div")){ if($("right_reslut_div").style.display==''){ $("right_reslut_div").innerHTML = ''; $("right_reslut_div").style.display = 'none'; } } } } var conRightMenu = new ConRightMenu();
分析以上代码如下:
1、
//orgCellColor存放点击行的原始颜色值 ConRightMenu.orgCellColor = ""; ConRightMenu.clickRow = "";
orgCellColor和clickRow分别存储的是点击行的原始背景颜色值和点击行的id,前者的作用是右键点击某一行设置了这行的背景值后再右键点击另一行时,把之前的那行的原始背景值再赋值给它;后者是得到点击某行的id值,这在设置右键按钮的事件中有很重要的作用。因为右键后显示的div的按钮与grid的按钮是不一样的,如果前者的onclick事件也和后者一样执行一个函数的话,那么是不行的。因为grid的按钮执行的函数里用到的event.srcElement等有关event事件的元素都与右键div的按钮的event事件的元素不一样,如果右键div的按钮执行grid的按钮的函数,就会出错。所以,我们解决方法是执行grid按钮的fireEvent("onclick")方法。这就要求能够取得到右键点击grid那行的按钮元素。通过clickRow得到tr的id,就可以定位到点击grid的那行的每个按钮元素了。可能有些抽象,大家认真看下代码就会明白了。
2、getTrObj()函数得到点击事件的那行tr这个obj。得到它后就可以定位到我们关心的任何东西了。注意这里的:Event.findElement(evt,"tr");和getEventElement()都很好重用。
3、changeClassForTD()用于设置右键某行后的背景颜色,因为右键的行要与其它行区分开来,所以用上背景颜色会比较直观。这里要注意的,右键某行时要把之前右键某行的保存的原始背景色赋值上去,这在前面的第一点的orgCellColor也讨论过了。这里通过trObj.parentElement.得到tr外面的table元素,再通过table元素的getElementsByTagName("TD")得到所有的td元素,如果td的背景色是#DCDCDC时则说明它是之前右键的那行,把它赋值为原始的值。这里要注意用了比较的两方都用了toUpperCase来得到颜色值,还要注意用backgroundColor,而不是background。
4、buttonClickFun()方法指定了右键按钮点击时执行的事件函数。写这个实现时发了挺多时间,走了弯路。本来想通过grid的每个按钮的id来得到每个按钮,但构造每个grid按钮的id名发了好多时间。后来想到,用如之前第一点说的用clickRow得到右键的那行,保存下来后。就可以得到这行下面的每个grid按钮了。
5、consButtonHtml()主要是通过自定义grid的按钮解析它们的html来得到右键内容。为什么要那样解析,其中前台jsp的自定义的写法如下:
<self:tag_grid tag_name='VOU_RECORD_GRID' is_right_menu = "true" custom_button=" <button title='编辑' class='gridBtnEdit' id='grid_custom_button_edit' onclick='vouRecordJsMgr.preEditVouRec();'> <button title='删除' class='gridBtnDel' id='grid_custom_button_del' onclick='vouRecordJsMgr.delVouRec(1);'> "></self:tag_grid>
上面的custom_button=""的内容就是我们要解析和构造的。
同时,用到的css如下:
.mouseOverGrid{ background-color:#C0C0C0; } .mouseOutGrid{ background-color:#DCDCDC; } .rowSplit { height: 3px; background: url(Image/m_splitLine.gif) repeat-x; font-size: 0px; margin: 0 2px; }
6、buildRightMenu()是构建右键菜单的主要生成代码。它主要做了三件事:一是取得右键的行的id即ConRightMenu.clickRow;第二件事是通过consButtonHtml()取得构造右键div的html,并设置这个div的属性,如style属性等;第三件事是设置右键行的背景色。其中设置style属性是为了美观和正确的定位。要注意的是left和top值要加上滚动条的值,因为鼠标的位置取的是文档坐标。代码如下:
function Geometry(){} Geometry.prototype = { getHorizontalScroll:function(){ var result = 0; // All browsers but IE if (window.innerWidth) { result = window.pageXOffset; } // for IE 6 when there is a DOCTYPE if (document.documentElement && document.documentElement.clientWidth) { result = document.documentElement.scrollLeft; } // for IE4, IE5, and IE6 without a DOCTYPE if (document.body.clientWidth) { result = document.body.scrollLeft; } return result; }, getVerticalScroll:function(){ var result = 0; // All browsers but IE if (window.innerWidth) { result = window.pageYOffset; } // for IE 6 when there is a DOCTYPE if (document.documentElement && document.documentElement.clientWidth) { result = document.documentElement.scrollTop; } // for IE4, IE5, and IE6 without a DOCTYPE if (document.body.clientWidth) { result = document.body.scrollTop; } return result; } } var geometry = new Geometry();
7、display_right_div()方法是当右键点击body时把右键隐藏掉。
以上大致介绍了自定义grid里用右键来实现功能菜单的操作过程,总体的过程就是那样了,希望对大家会有帮助。
最终的效果如下: