今天,我们说说使用Deeptree的一个心得技巧。可能还有不知道Deeptree是什么的兄弟,deeptree是微软最早使用在msdn里作为导航树的,在ajax大行其道之前已经以优秀的设计及出众的性能(不是一次性加载数据,而是使用的时候再加载,套句术语就是属于“lazy loading”)为广大开发者争相采用。
下面,简单介绍下deeptree的组成,它主要包括以下几个文件:
deeptree.htc:负责处理数据加载,用户事件
deeptree.xsl:负责将xml数据格式化为html,展现给用户
deeptree.css:负责树的显示风格
server.asp:负责从服务器获取数据
Deeptree一般是使用单表作为数据源的,表结构一般是类似这样:
栏目表
| 列名 |
列类型 |
| 栏目ID |
自增数字型 |
| 栏目名称 |
字符型
|
| 父栏目ID |
数字型
|
deeptree在生成树的过程中,一般流程如下:
- htc里定义了server.asp和deeptree.xsl文件
var Config={
loading:"正在加载,请稍候...",//加载时显示信息
unavaible:"加载失败,请检查...",//加载失败时显示信息
Service:"getAreaByType.asp",//节点数据文件
SyncXSLsrc:"deeptree_area.xsl",//一次加载时xsl文件
isExpandOne:true //同一级别是否只允许打开一个节点
}
- htc里调用Init()方法初始化数据
function Init(){
GetXml(element,0)
}
- GetXml(objContainer,id)方法从服务器获取数据(XMLHTTP),格式如下:
<?xml version="1.0" encoding="gb2312"?>
<xml>
<TreeNode id="1">
<NodeText>旅游</NodeText>
<title></title>
<NodeUrl>searchform.php?fdIcoId=1</NodeUrl>
<child>2</child>
<target>showresult</target>
</TreeNode>
<TreeNode id="4">
<NodeText>房产</NodeText>
<title></title>
<NodeUrl>searchform.php?fdIcoId=4</NodeUrl>
<child>5</child>
<target>showresult</target>
</TreeNode>
</xml>
- xml数据+deeptree.xsl文件处理,生成html并显示
- 当用户点击节点的时候,调用htc里的ExpandNode(objNode)方法加载数据(GetXml)
下面,是一个deeptree处理多表的问题,这里是一个地区数据,分为国、省、市三级,这三级的数据分别存在三张表里,如下:
国家
| 列名 |
列类型 |
| 国家ID |
自增数字型 |
| 国家名称 |
字符型 |
省份
| 列名 |
列类型 |
| 省份ID |
自增数字型 |
| 省份名称 |
字符型 |
| 国家ID |
数字型,外键 |
地市
| 列名 |
列类型 |
| 地/市ID |
自增数字型 |
| 地/市名称 |
字符型 |
| 省份ID |
数字型,外键 |
问题来了,如何在用户点击节点的时候,判断用户当前点击的是国家、省份还是地市呢?
我的处理方法是这样的:
- 修改GetXml方法,添加一个areaType参数:
function GetXml(objContainer,id,areaType){
var XmlHttp=new ActiveXObject("Microsoft.XMLHTTP")
objContainer.innerHTML=StateXML(Config.loading)
objContainer.send="true"
XmlHttp.onreadystatechange=function(){
if(XmlHttp.readyState==4){
if(XmlHttp.status==200){
var Xmldoc=XmlHttp.responseXML
if(Xmldoc.documentElement.hasChildNodes())
objContainer.innerHTML=Xmldoc.transformNode(xsldoc)
else
objContainer.innerHTML=StateXML(Config.loading)
}
else
objContainer.innerHTML=StateXML(Config.unavaible)
}
}
var url=Config.Service+'?id='+id+'&areaType='+areaType+'&tem'+Math.random()
//alert(url)
XmlHttp.open("get",url,true)
XmlHttp.send()
}
- 初始化的时候,areaType默认设为country
function Init(){
GetXml(element,0,"country")
}
- 修改ExpandNode方法
function ExpandNode(objNode){
var oImg=GetElement(objNode,"img")
var oNode=GetElement(objNode,"span")
var oChild=objNode.nextSibling
oImg.src=icon.open.src
oChild.style.display=""
objNode.open="true"
//alert(objNode.areaType)
if(oChild.send=="false")GetXml(oChild,objNode.uid,objNode.areaType)
if(Config.isExpandOne){
var oContainer=objNode.parentElement
var oChildren=oContainer.children
for(i=0;i<oChildren.length;i++)
if(oChildren[i].open=="true"&&oChildren[i]!=objNode)CollapseNode(oChildren[i])
}
}
- 修改XML数据格式,添加areaType属性:
<?xml version="1.0" encoding="gb2312"?>
<xml>
<TreeNode id="1" areaType="province">
<NodeText>安哥拉</NodeText>
<title></title>
<NodeUrl>DD_Area_Form.asp?id=1&title=安哥拉&type=country</NodeUrl>
<child>0</child>
<target>mainFrame</target>
</TreeNode>
</xml>
- 修改deeptree.xsl文件,为生成的树节点(div)增加areaType属性,使用xpath从xml数据中获取areaType的值:
<xsl:attribute name="areaType"><xsl:value-of select="@areaType"/></xsl:attribute>
- 修改数据读取程序,其中有个问题,如何判断用户当前点击的是国家、省份还是地市?我们从代码的角度进行分析下,从第二步可以看到,初始化的时候:id=0,areaType=country,系统初始化以后会首先取得国家表的数据,那么当我们点击节点,希望取得的是某个国家内的省份数据,处理方式为:
- 判断id是否为0,若为0则设置xml数据的areaType属性值为province(省)
- 点击节点的时候激活ExpandNode方法,通过GetXml访问如下Xml:
http:/getAreaByType.asp?id=37&areaType=province
取得如下xml数据:
<?xml version="1.0" encoding="gb2312"?>
<xml>
<TreeNode id="1" areaType="city">
<NodeText>北京市</NodeText>
<title></title>
<NodeUrl>DD_Area_Form.asp?id=1&title=北京市&type=province</NodeUrl>
<child>1</child>
<target>mainFrame</target>
</TreeNode><TreeNode id="2" areaType="city">
<NodeText>天津市</NodeText>
<title></title>
<NodeUrl>DD_Area_Form.asp?id=2&title=天津市&type=province</NodeUrl>
<child>1</child>
<target>mainFrame</target>
</TreeNode>
</xml>
- 此时就会显示某国家的省份数据,此时id不等于0,那么我们可指定areaType=city,那么当用户单击省份的时候就会获取城市的数据:
<?xml version="1.0" encoding="gb2312"?>
<xml>
<TreeNode id="134" areaType="city">
<NodeText>南昌市</NodeText>
<title></title>
<NodeUrl>DD_Area_Form.asp?id=134&title=南昌市&type=city</NodeUrl>
<child>0</child>
<target>mainFrame</target>
</TreeNode><TreeNode id="135" areaType="city">
<NodeText>景德镇市</NodeText>
<title></title>
<NodeUrl>DD_Area_Form.asp?id=135&title=景德镇市&type=city</NodeUrl>
<child>0</child>
<target>mainFrame</target>
</TreeNode>
</xml>
- 总结下,这里的问题关键是以下几个方面:
- 为xml数据增加areaType属性;
- 修改deeptree.xsl文件,添加areaType属性;
- 修改deeptree.htc文件,添加areaType参数;
- 根据id来判断地区类型。
- 附:getAreaType.asp源代码:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%>
<!--#include file="../System/Conn.asp" -->
<%
'项目类型
dim id,areaType,target
id = request.QueryString("id")
areaType = request.QueryString("areaType")
target = "mainFrame"
if areaType = "" then
areaType = "country"
end if
'项目类型数据集
dim rs
'查询项目类型sql字符串
dim sql,areaId,areaName

if areaType = "province" then
sql = "select province_id,province_name from d_Province where country_id="& id &" order by province_id"
areaId = "province_id"
areaName = "province_name"
elseif areaType = "city" then
sql = "select city_id,city_name from d_City where province_id="& id &" order by city_id"
areaId = "city_id"
areaName = "city_name"
elseif areaType = "country" then
sql = "select Country_id,Country_Chinese_Name from D_Country order by Country_id"
areaId = "Country_id"
areaName = "Country_Chinese_Name"
end if

'打开数据集
set rs=Conn.execute(sql)
'定义xml字符串变量
dim xml
xml = "<?xml version=""1.0"" encoding=""gb2312""?> " & vbcrlf
xml = xml & "<xml>" & vbcrlf
'循环xml文件数据体
while (not rs.eof)
xml = xml & "<TreeNode id="""& rs(areaId) &""" areaType="""& getAreaType(id) &""">" & vbcrlf
xml = xml & "<NodeText>" & rs(areaName) & "</NodeText>" & vbcrlf
xml = xml & "<title></title>" & vbcrlf
xml = xml & "<NodeUrl>" & getUrl(rs(areaId),areaType,rs(areaName)) & "</NodeUrl>" & vbcrlf
xml = xml & "<child>" & getChildNum(rs(areaId),areaType) & "</child>" & vbcrlf
xml = xml & "<target>" & target & "</target>" & vbcrlf
xml = xml & "</TreeNode>"
rs.movenext()
wend
xml = xml & "</xml>" & vbcrlf

'关掉连接释放资源
rs.close()
conn.close()
set rs = nothing
set conn = nothing

function getUrl(areaId,areaType,areaName)
dim url
if areaType = "country" then
url = "DD_Area_Form.asp?id="& areaId & "&title=" & areaName & "&type=country"
elseif areaType = "province" then
url = "DD_Area_Form.asp?id="& areaId & "&title=" & areaName & "&type=province"
elseif areaType = "city" then
url = "DD_Area_Form.asp?id="& areaId & "&title=" & areaName & "&type=city"
end if
getUrl = url
end function

function getChildNum(areaId,areaType)
dim iCount
if areaType = "country" then
sql2 = "select count(1) as iCount from D_Province where Country_Id="& areaId
elseif areaType = "province" then
sql2 = "select count(1) as iCount from D_City where Province_Id="& areaId
elseif areaType = "city" then
getChildNum = "0"
exit function
end if
set rsCount1 = conn.execute(sql2)
iCount = rsCount1("iCount")
rsCount1.close
set rsCount1 = nothing
getChildNum = iCount
end function

function getAreaType(areaId)
if areaId = "0" then
getAreaType = "province"
elseif areaId<>"" and areaId<>"0" then
getAreaType = "city"
end if
end function

'输出xml文件
response.ContentType="text/xml"
response.Charset="gb2312"
response.Write(xml)
%>
发表于 @ 2007年10月16日 10:40:00|评论(loading...)|编辑