答案:在开发网络应用程序时,常常会遇到多级选择的问题,即“子”一级选择的备选项信息依赖于“父”一级选择的数据。例如:在一个网页中包含两个select输入控件,一个用于列表备选的国家信息(“父”一级选择),另一个用于列表省份信息(“子”一级选择)。当用户在第一个select输入控件(“父”一级选择)中选中国家后,另一个select输入控件(“子”一级选择)的选项也要变为相应国家的省、州选项,而他们之间的关系动态地保存在数据库中。
提出问题
传统的解决方法可以描述为:用户选中“父”一级选择后,通过form提交的方式,由相应的处理程序从数据库中提取“子”一级选择的信息,并刷新客户端页面中“子”一级选择的数据。
采用这种方法的缺点是:
●必须编写一个或多个ASP程序分别处理用户的请求,程序代码质量不高;
●当级数超过两级时,必须解决“祖父”一级的选择信息的保存问题;
●每一次用户的修改或浏览多级信息,都必须重复提交以获得多级信息,这样,增易做图务器的负担,响应速度较慢。
针对以上方案中存在的问题,笔者在实践中找到了一种解决方法。该方法灵活应用HTML语言中的输入控制对象hidden,当hidden中的数据量小于2K时,可一次性将多级信息下载到客户端,并通过服务器端脚本与客户端脚本的共同作用,直接在客户端完成多级选择。
解决方法
HTML语言中的输入控制对象hidden可以通过name-value的方式存储字符串数据,而且该控制对象在客户端界面上不可见。
利用该输入控制,可以将数据库中多级选择信息按照一定的规则编码,分别存放在多个hidden对象中。当用户点击父级选项时,客户端程序按照一定的对应关系查找相应的hidden对象,并将hidden对象中的字符串信息解码,刷新子级选择对象。
其中,服务器端脚本需要完成的工作是将数据库中的多级信息按照顺序依次提取,并且将同级的信息数据按照一定规则编码形成字符串,存储在不同的hidden对象中;而客户端脚本需要完成的工作是将hidden对象中的字符串数据解码,并显示在子级选择对象中。
需要特别指出的是,数据的字符串编码是此种方法成功与否的一个关键因素,因此必须保证编码方易做图确无误。
具体实现
下面以国家、省份两级选择为例,介绍在ASP中多级选择的具体实现方法。
在SQL Server 7.0数据库CountryDoc中存放两级信息的表分别为CountryName char(20)和ProvinceName char(20)。
考虑到国家名、省/州名为字符串数据,且不包含字符“0”,因此在选择编码方法时,采用5个连续的字符“0”作为不同数据项之间的分隔符。编码后的省份数据具体形式为“北京00000上海00000黑龙江00000吉林”。
<html><head>
<script language=vbscript>
dim ProvinceArr()
dim ProvinceNum ,ProvinceStr
//字符串解码,将由‘00000'分开的选项回存到相应的动态数组中
sub myStrToArray
dim i,tmpInt,tmpStr
redim ProvinceArr(ProvinceNum-1)
tmpStr=ProvinceStr
for i=0 to ProvinceNum-1 step 1
tmpInt=InStr(tmpStr,“00000”)
ProvinceArr(i)=Left(tmpStr,tmpInt-1)
tmpStr=Right(tmpStr,Len(tmpStr)-tmpInt-4)
next
end sub
//向省级选择select对象中添加一个备选项
sub AddOption(OptionStr)
dim oOption
set oOption=document.createElement(“OPTION”)
oOption.value=OptionStr
oOption.text=OptionStr
form1.ProvinceList.add(oOption)
end sub
//清除省级选择select对象的所有备选项(第一项除外)
sub ClearOption
dim count,i
count=form1.ProvinceList.length
if count<=1 then
exit sub
end if
for i=count-1 to 1 step -1
form1.ProvinceList.remove(i)
next
end sub
//当用户选中国家级备选项时,更新省级备选项中的数据
sub CountryList_onChange
dim CountryName,i
//获得国家名称
CountryName=form1.CountryList.value
if CountryName=“none”then
exit sub
end if
//根据国家名称查找相应的hidden对象,并从中取出省份、州数据(字符串)
for i=0 to form1.elements.length-1 step 1
if inStr(form1.elements(i).name,CountryName & “Arr”)>0 andform1.elements(i).tagName=“INPUT” then
ProvinceStr=form1.elements(i).value
end if
if form1.elements(i).tagName=“INPUT”and inStr(form1.elements(i).name,CountryName & “Num”)>0 then
ProvinceNum=form1.elements(i).value
end if
next
if ProvinceNum=0 then
exit sub
end if
//清除省级选择中的数据(除第一项以外)
ClearOption
//字符串解码(字符串形式的省级数据存放在全局变量ProvinceStr中)
myStrToArray
//重新构造省级选择中的数据信息
for i=0 to ProvinceNum-1 step 1
AddOption(ProvinceArr(i))
next
form1.ProvinceList.selectedIndex=0
end sub
</script>
</head>
<body>
<form name=form1>
<table align=center>
<tr><td>国家</td>
<td>省份、州</td></tr>
<tr><td><select name=CountryList>
<option value=none>_______________</option>
<%@ Language=VBScript %>
<% dim CountryArr() %>
<% i=0 %>
//提取表中的所有国家选项,并写入国家级选择控件
<% sqlText=“select distinct CountryName from CountryDoc” %>
<% set rs=conn.Execute(sqlText) %>
<% do while not rs.EOF %>
<% i=i+1 %>
<% redim preserve CountryArr(i) %>
//将国家级数据写入动态数组中
<%CountryArr(i-1)=Trim(rs(“CountryName”))%>
<optionvalue=<%=Trim(r(“CountryName”))%>>
<%=Trim(rs(“CountryName”))%></option>
<% rs.MoveNext %>
<% loop %>
<% rs.Close %>
<% CountryNum=I %>
</select>
</td><td>
<select name=ProvinceList>
<option value=none>_______________</option>
</select></td></tr></table>
//依次从动态数组中提取国家名称,并提取对应的省级数据信息
<% for i=0 to CountryNum-1 step 1 %>
<% temp1=CountryArr(i) %>
<% ProvinceNum=0 %>
<% sqlText=“select count(*) as RecordNum from CountryDoc where CountryName=‘“& temp1 & ”’” %><% set rs=conn.Execute(sqlText) %>
<% ProvinceNum=rs(“RecordNum”) %>
<% rs.Close %>
<% ProvinceStr=“” %>
<% sqlText =“select ProvinceName from CountryDoc where CountryName =‘“ & temp1 & ”’” %>
<% set rs=conn.Execute(sqlText) %>
<% do while not rs.EOF %>
//将省级信息字符串编码(以“00000”分隔)
<%ProvinceStr=ProvinceStr & Trim(rs
(“ProvinceName”)) & “00000” %>
<% rs.MoveNext %>
<% loop %>
<% rs.Close %>
//将编码后的省级数据写入hidden对象中
<% Response.Write(“<input type=hidden name=” & temp1 & “Arr value=” & ProvinceStr & “ >”) %>
//保存数据项个数
<% Response.Write(“<input type=hidden name=” & temp1 & “Num value=” & ProvinceNum & “ >”) %>
<% next %>
<% set rs=nothing %>
<% conn.close %>
<% set conn=nothing %>
</form></body></html>
以上代码在NT 4.0+IIS 4.0+SQL Server 7.0+IE 5.0环境中运行通过。
由于整个工作都在一个ASP程序中完成,并且所有数据一次性下载到客户端,用户选择时不存在“祖父”一级的选择信息的保存问题(没有刷新的工作)。
小 结
如果数据量不大的话,采用本文介绍的方法是可行的。但是当一个hidden中存储的数据量超过2K时,受到HTML语言的自身限制,可能会存在hidden对象中数据丢失或缺少的问题,此时建议仍采用表单提取的方法来完成多级选择。
上一个:提高浏览器的调试能力
下一个:用ASP实现树形目录视图