JS实现联想输入(二)

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代码如何实现下拉列表的形式展现数据并形成联想输入的样子!
上一篇:Ramnit蠕虫病毒分析和查杀


下一篇:挑战10个最难回答的Java面试题(附答案)