JS實現聯想輸入(一)是主要針對單列結構的JSON格式的數據的,如果想滿足多列結構的JSON格式的數據,也是非常容易的,其解決方案有至少有三種選擇:
1:在后台Action方法中將多列的值拼成單列結構的值,然后和JS實現聯想輸入(一)中的實現方式沒什么大的變化,只是在前台看數據時有點怪怪的(比如用“|”隔開的情景下),而且需要在前台將對應數劇拆開來用
2:利用聯想輸入框中的數據,再次的調用AJAX方法到后台去查詢對應的數據,也和JS實現聯想輸入(一)中的實現方式沒什么大的變化,只是又多調用了一下后台的Action方法,當然他有一些局限性,如果聯想輸入框中的數據到后台作為參數不能唯一定位到一條數據的話,就有些不適用了
3:第三種方式就是我下面要分享的一種方式了,從后台返回多列結構的JSON格式的數據(一般兩列就足夠了,一列是表的主鍵數據列,另一列是要顯示的作為聯想輸入的數據列)在前台用兩個TD封裝,一個顯示其中的內容,另一個則隱藏。實現的方式和JS實現聯想輸入(一)也基本類似,只是從后台Action方法中返回的數據是雙列結構的JSON數據(當然,你也可以使用其他格式的數據)和拼裝下拉列表的方式所有不同而已
下面是我要分享的代碼段,僅作為我的小小的記錄而已!
1:首先同樣是后台的Action方法的代碼,用於取數據,查詢語句是模糊查詢的方式(如果數據庫中的數據相似度非常大,可以采用分頁的方式取部分的數據,比如:取十條記錄)。
/** * @說明:這仍是一段偽碼,主要想說明從后台返回的數據是JSON格式的,並且形如:[{"linkDataName":name1,"linkDataId":id1},{"linkDataName":name2,"linkDataId":id2},{"linkDataName":name3,"linkDataId":id3}] * @author godtrue * @修改時間:2014-02-24 * @param * @return */ public void getLinkDataList(){ linkData.setLinkDataName(linkDataName); List<LinkData> linkDataList = linkDataService.getLinkDataList(linkData); if(linkDataList!=null&&linkDataList.size()>0){ StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("["); for(int i=0;i<linkDataList.size()-1;i++){ stringBuffer.append("{\"linkDataName\":\"").append(linkDataList.get(i).getLinkDataName()).append("\","); stringBuffer.append("\"linkDataId\":\"").append(linkDataList.get(i).getLinkDataId()).append("\"},"); } stringBuffer.append("{\"linkDataName\":\"").append(linkDataList.get(linkDataList.size()-1).getLinkDataName()).append("\","); stringBuffer.append("\"linkDataId\":\"").append(linkDataList.get(linkDataList.size()-1).getLinkDataId()).append("\"}]"); renderJson(ServletActionContext.getResponse(),stringBuffer.toString()); }else{ renderJson(ServletActionContext.getResponse(),"[]"); } }
renderJson方法的源碼和JS實現聯想輸入(一)中renderJson方法的源碼是一模一樣的再次就不再給出了!
說明:同樣假設上面的代碼中LinkData是一個對象其中他擁有兩個屬性分別是linkDataName和linkDataId(在此Aciton類中有linkData和linkDataName的聲明和對應的SET/GET方法,所以們的值在前后台能相互的傳送,並且linkDataId屬性對應的數據庫中表的列能夠唯一的標示出數據庫中的一條記錄),linkDataService是業務層的一個接口對象,它調用對應的方法獲得對應的模糊查詢的數據結果集linkDataList,然后將結果集中的數據封裝成雙列結構的JSON格式的數據形如:[{"linkDataName":name1,"linkDataId":id1},{"linkDataName":name2,"linkDataId":id2},{"linkDataName":name3,"linkDataId":id3}]
2:前台JSP中的HTML代碼,這段代碼同樣主要是展示HTML輸入框和為聯想輸入的下拉選項列表做支撐的(此段代碼和JS實現聯想輸入(一)中的對應的代碼基本一模一樣,只是多了一個樣式"z-indexe:1001"以使下拉列表處在頁面的最上層,當然這是在需要的情況下才添加此樣式的,在我們的項目中就需要這個,當然還有一個隱藏域專門來接收linkDataId屬性的數據,只要將他放在FORM表單中就可)
<td><input id="linkDataId" name="linkData.linkDataId" type="hidden"></input><input style="width:100%;" id="linkDataName" name="linkData.linkDataName" type="text" onkeyup="getLinkData();" /> <div id="popup" style="position: absolute;z-index:1001;"> <table width="100%" bgcolor="#fffafa"> <tbody id="popupBody"></tbody> </table> </div> </td>
3:前台JSP中的javaScript代碼,當然這段代碼具有一定的通用性,最好封裝在一個單獨的js文件中更好一些(這也是實現此功能最為關鍵的一段代碼,原理很簡單:利用ajax動態調用后台的方法獲取對應的聯想輸入的數據,然后將數據拼裝成下拉選項列表的形式,再在對應的列表選項上添加對應的事件來控制選中的選項數據,只是和JS實現聯想輸入(一)的不同在於,這次的事件加在了TR上,並且隱藏了一列我們不想讓用戶看到的TD列)
function getLinkData() { var popupDiv = document.getElementById("popup");//獲得對應的div對象 var popupBody = document.getElementById("popupBody");//獲得對應的tbody對象 var linkDataName = document.getElementById("linkDataName"); //獲得對應的聯想輸入框對象 var linkDataId = document.getElementById("linkDataId"); //獲得對應的隱藏域對象 clearModels();//清除聯想輸入提示框的內容 $.ajax({ type : "post",//提交的方法為post url : "getLinkDataList.action",//提交的路徑 dataType : "json", //從Action中返回的值得類型為json類型的 data:{linkDataName:linkDataName.value},//從前台傳遞到后台的參數,可以避免出現亂碼的情況 error:function(){ alert("沒有對應的數據,請查看輸入的查詢條件!"); }, success : function(data) {//當Ajax提交成功時調用的方法 if(data.length==0||data=="[]"){return;} setOffsets();//設置聯想輸入提示框的位置及樣式 var tr,td,text,td_,text_; for (var i = 0; i < data.length; i++) {//根據返回的值,手動的拼tbody的內容,此為此功能的核心代碼 text = document.createTextNode(data[i].linkDataName);//從Action中返回的數據中取出linkDataName的值 td = document.createElement("td");//創建一個td的對象 tr = document.createElement("tr");//創建一個tr的對象 text_ = document.createTextNode(data[i].linkDataId);//從Action中返回的數據中取出linkDataId的值 td_ = document.createElement("td");//創建一個另一個td的對象 td_.style.display="none"; //並且設置其樣式是不可見的 td.appendChild(text); td_.appendChild(text_); tr.appendChild(td); tr.appendChild(td_); tr.mouseOver = function(){this.className="mouseOver;";}; tr.mouseOut = function(){this.className="mouseOut;";}; tr.onclick = function(){populateModel(this);};//tr單擊事件對應的實現方法 popupBody.appendChild(tr); } }}); //獲取下拉列表項的內容,初始化相關的數據 function populateModel(cell) { clearSelect(); linkDataName.value = cell.firstChild.firstChild.nodeValue; linkDataId.value=cell.lastChild.lastChild.nodeValue; clearModels();//清除自動完成行 } //清除自動完成行,只要tbody有子節點就刪除掉,並且將將外圍的div的邊框屬性設置為不可見的 function clearModels() { while (popupBody.childNodes.length > 0) { popupBody.removeChild(popupBody.firstChild); } popupDiv.style.border = "none"; } //設置下拉列表框的的位置及樣式 function setOffsets() { var width = linkDataName.offsetWidth+20;//如果下拉列表中有折疊的行,可以在此加大些寬度 var left = getLeft(linkDataName); var top = getTop(linkDataName) + linkDataName.offsetHeight; popupDiv.style.border = "black 1px solid"; popupDiv.style.left = left + "px"; popupDiv.style.top = top + "px"; popupDiv.style.width = width + "px"; } //獲取指定元素在頁面中的寬度起始位置 function getLeft(e) { var offset = e.offsetLeft; if (e.offsetParent != null) { offset += getLeft(e.offsetParent); } return offset; } //獲取指定元素在頁面中的高度起始位置 function getTop(e) { var offset = e.offsetTop; if (e.offsetParent != null) { offset += getTop(e.offsetParent); } return offset; } } //清空聯想輸入框的內容以及隱藏域的值 function clearSelect() { var linkDataId = document.getElementById("linkDataId"); linkDataId.value = ""; var linkDataName = document.getElementById("linkDataName"); linkDataName.value = ""; }
注:此方法對於雙列結構的集合是適用的,大部分代碼和JS實現聯想輸入(一)是一致的,僅在數據的傳送和拼裝上做了少許的變動,關鍵的地方在於前台的JS代碼如何實現下拉列表的形式展現數據並形成聯想輸入的樣子!
