DeepTree在多表中的应用

原创 2007年10月16日 10:40:00

今天,我们说说使用Deeptree的一个心得技巧。可能还有不知道Deeptree是什么的兄弟,deeptree是微软最早使用在msdn里作为导航树的,在ajax大行其道之前已经以优秀的设计及出众的性能(不是一次性加载数据,而是使用的时候再加载,套句术语就是属于“lazy loading”)为广大开发者争相采用。

下面,简单介绍下deeptree的组成,它主要包括以下几个文件:

deeptree.htc:负责处理数据加载,用户事件
deeptree.xsl:负责将xml数据格式化为html,展现给用户
deeptree.css:负责树的显示风格
server.asp:负责从服务器获取数据

Deeptree一般是使用单表作为数据源的,表结构一般是类似这样:

栏目表
列名 列类型
栏目ID 自增数字型
栏目名称

字符型

父栏目ID

数字型

deeptree在生成树的过程中,一般流程如下:

  1. htc里定义了server.asp和deeptree.xsl文件
    var Config={
        loading:
    "正在加载,请稍候...",//加载时显示信息
        unavaible:"加载失败,请检查...",//加载失败时显示信息
        Service:"getAreaByType.asp",//节点数据文件
        SyncXSLsrc:"deeptree_area.xsl",//一次加载时xsl文件
        isExpandOne:true //同一级别是否只允许打开一个节点
    }
  2. htc里调用Init()方法初始化数据
    function Init(){
        GetXml(element,
    0)
    }
  3. 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>
  4. xml数据+deeptree.xsl文件处理,生成html并显示
  5. 当用户点击节点的时候,调用htc里的ExpandNode(objNode)方法加载数据(GetXml)

下面,是一个deeptree处理多表的问题,这里是一个地区数据,分为国、省、市三级,这三级的数据分别存在三张表里,如下:

国家
列名 列类型
国家ID 自增数字型
国家名称 字符型

省份
列名 列类型
省份ID 自增数字型
省份名称 字符型
国家ID 数字型,外键

地市
列名 列类型
地/市ID 自增数字型
地/市名称 字符型
省份ID 数字型,外键

问题来了,如何在用户点击节点的时候,判断用户当前点击的是国家、省份还是地市呢?

我的处理方法是这样的:

  1. 修改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()
    }
  2. 初始化的时候,areaType默认设为country
    function Init(){
        GetXml(element,
    0,"country")
    }
  3. 修改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])        
        }
    }
     
  4. 修改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&amp;title=安哥拉&amp;type=country</NodeUrl>
    <child>0</child>
    <target>mainFrame</target>
    </TreeNode>
    </xml>
  5. 修改deeptree.xsl文件,为生成的树节点(div)增加areaType属性,使用xpath从xml数据中获取areaType的值:
    <xsl:attribute name="areaType"><xsl:value-of select="@areaType"/></xsl:attribute>
  6. 修改数据读取程序,其中有个问题,如何判断用户当前点击的是国家、省份还是地市?我们从代码的角度进行分析下,从第二步可以看到,初始化的时候:id=0,areaType=country,系统初始化以后会首先取得国家表的数据,那么当我们点击节点,希望取得的是某个国家内的省份数据,处理方式为:
    1. 判断id是否为0,若为0则设置xml数据的areaType属性值为province(省)
    2. 点击节点的时候激活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&amp;title=北京市&amp;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&amp;title=天津市&amp;type=province</NodeUrl>
      <child>1</child>
      <target>mainFrame</target>
      </TreeNode>
      </xml>
    3. 此时就会显示某国家的省份数据,此时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&amp;title=南昌市&amp;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&amp;title=景德镇市&amp;type=city</NodeUrl>
      <child>0</child>
      <target>mainFrame</target>
      </TreeNode>
      </xml>
  7. 总结下,这里的问题关键是以下几个方面:
    1. 为xml数据增加areaType属性;
    2. 修改deeptree.xsl文件,添加areaType属性;
    3. 修改deeptree.htc文件,添加areaType参数;
    4. 根据id来判断地区类型。
  8. 附: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 & "&amp;title=" & areaName & "&amp;type=country"
        
    elseif areaType = "province" then
            url 
    = "DD_Area_Form.asp?id="& areaId & "&amp;title=" & areaName & "&amp;type=province"
        
    elseif areaType = "city" then
            url 
    = "DD_Area_Form.asp?id="& areaId & "&amp;title=" & areaName & "&amp;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在多表中的应用
举报原因:
原因补充:

(最多只允许输入30个字)