今天,我们说说使用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)
%
>

本文介绍了一种使用Deeptree处理多表数据的方法,通过添加areaType属性实现了不同层级数据的动态加载,并详细展示了实现过程。
4494

被折叠的 条评论
为什么被折叠?



