涂雅[博客园]
最新文章请访问独立博客:http://iove.net
  在周未的时间里,忙了两个小时,终于把示例代码写完了,虽然很累,但却很开心,因为我知道这个示例代码将会给很多人带来启发,它是有价值的,它的价值也将体现我的价值,不是么?
  在你看这篇文章之前,我想唠叨几句,我希望你在看文章也好,看示例代码也好,着重是看其中的思想与技巧,举一反三,而不是直接拿代码就去使用了。或许你会有更好的实现方法,没关系,我希望我这篇文章能起到抛砖引玉的作用,让我们一起进步。看这篇文章,你可能需要具备一些基础的知识,如Javascript、CSS、Xslt、Xml,当然这不是必需的,如果你悟性比较高的话。闲话少讲,言归正传,follow me!让我们步入Xslt神奇的殿堂吧
  首先,我们应该了解一下需求:
  1、要求在一个页面中有若干个标签块(即是由若干个标签组成的区域),并且通过Xslt格式化Xml
    2、具备扩展性,标签及签块可以在xml中自由添加
    3、鼠标移至不同的标签,会显示相应的内容
  
    我们知道,程序最重要的是在规划,在做之前我们也应该要规划一下,我初步实现的思路是这样的,用xml描述布局、标签块及标签的信息,通过xslt循环布局信息,然后再循环标签块信息,再循环标签及内容信息。
    这样就需要经过三层循环,最后一层循环需要两次循环,第一次是循环标签标题,第二次是循环标签内容。最后一层循环还需要做一个事情调用一个javascript函数,把当前标签块及内容块的元素ID,以便注册事件,关于这个函数的详细说明,请参考拙作用DIV+Javascript实现标签功能
    现在我们重点来规划一下xml,xml的结构是否合理,直接影响到xslt的编写,首先我们看一下xml的基本结构,然后根据示例再作说明
 <?xml version="1.0" encoding="UTF-8"?>  
 <?xml-stylesheet type="text/xsl" href="index.xsl" ?>  
 <Root>  
  <!--栏目列表-->  
  <Columus Class="LeftSide">  
   <!--标签块列表-->  
   <Labels>  
    <!--相应的标签-->  
    <Label>  
     <Caption><![CDATA[标签1]]></Caption>  
     <Content><![CDATA[内容1]]></Content>  
    </Label>  
    <!--更多标签...-->  
   </Labels>  
   <!--更多的标签块...-->  
  </Columus>  
 <!--更多栏目...-->  
  </Root>

  我们首先将页面采用三分栏的布局,用Columus节点来描述布局信息,并增加一个Class的属性;在每一个分栏中,会有若干个标签块,用Labels节点来描述标签块;在每一个标签块中,会有若干个标签,用Label节点来描述;而在每一个标签中,又会由一个标签标题及内容组成,我们用Caption描述标签标题,用Content描述内容信息。

  现在我们看看xml的结构,是不是很简洁,如果需要再添加标签或者标签块,我只需要在相应的位置添加描述信息就可以了,比如说,我要第一栏的第一个标签块中增加一个标签,就可以这样写:
 <?xml version="1.0" encoding="UTF-8"?>  
 <?xml-stylesheet type="text/xsl" href="index.xsl" ?>  
 <Root>  
  <Columus Class="LeftSide">  
   <Labels>  
    <Label>  
     <Caption><![CDATA[标签1]></Caption>  
     <Content><![CDATA[内容1]]></Content>  
    </Label>  
   <!--添加Label节点,就可以实现添加标签-->  
    <Label>  
     <Caption><![CDATA[这是增加的标签]></Caption>  
     <Content><![CDATA[内容2]]></Content>  
    </Label>  
   </Labels>  
  </Columus>  
  </Root>
  xml结构完成了,也就成功了一半(其实还有一个重要的工作是javascript,因为javascript在另一个例子已经讲过了,所以不用再编写了),接下来该轮到xslt这位兄弟粉墨登场了,核心代码如下:
 <!--第一层循环,循环出布局信息-->  
 <xsl:for-each select="Root/*">  
  <xsl:variable name="_Class" select="@Class" />  
  <!--将class信息添加到div中-->  
  <div class="{$_Class}">  
   <!--这个地方很重要,因为我们要每一个标签组取一个全局唯一的id名称,所以需要两次用到position()这个属性来确定唯一的名称-->  
   <xsl:variable name="_LabelsIndex" select="position()" />  
   <!--第二层循环,循环出标签组信息-->  
   <xsl:for-each select="Labels">  
     <!--再次取当前的索引信息,用上一层的索引信息与本层的索引信息来确定唯一的名称-->  
    <xsl:variable name="Index"><xsl:value-of select="$_LabelsIndex" /><xsl:value-of select="position()" /></xsl:variable>  
    <xsl:variable name="LabelName">Label<xsl:value-of select="$Index" /></xsl:variable>  
    <xsl:variable name="ContainerName">Container<xsl:value-of select="$Index" /></xsl:variable>  
    <!--标签-->  
    <ul id="{$LabelName}" class="Labels">  
     <!--第三层循环的第一个循环,循环出标签标题信息,只所以在第三层要做两次循环,是因为我们要将标签信息和内容信息分别放在两个不同的容器中-->  
     <xsl:for-each select="Label/Caption">  
      <li>  
        <!--如果当前是索引是第一个,则添加Currentlabel这个class-->  
       <xsl:if test="position() = 1">  
        <xsl:attribute name="class">Currentlabel</xsl:attribute>  
       </xsl:if>  
       <!--.相当于current()这个函数,就是列出当前节点的内容-->  
       <xsl:value-of select="." disable-output-escaping="yes"/>  
      </li>  
     </xsl:for-each>  
    </ul>  
    <!--当前标签组的内容组容器,一定要有id,因为javascript需要通过这个id循环子节点,以获取不同的内容-->  
    <div id="{$ContainerName}" class="Container">  
     <!--第三层循环的第二个循环,循环出标签内容信息-->  
     <xsl:for-each select="Label/Content">  
      <div>  
      <!--如果当前是索引不是第一个,则用display:none这个属性将其隐藏-->  
       <xsl:if test="position() != 1">  
        <xsl:attribute name="style">display: none</xsl:attribute>  
       </xsl:if>  
       <xsl:value-of select="." disable-output-escaping="yes"/>  
      </div>  
     </xsl:for-each>  
    </div>  
    <!--调用RegisterEvent为所有的标签注册事件-->  
    <script language="javascript">  
     RegisterEvent ("<xsl:value-of select="$LabelName" />", "<xsl:value-of select="$ContainerName" />");   
    </script>  
   </xsl:for-each>  
  </div>  
 </xsl:for-each>
  这里的重点是一是多次用到了position()这个属性,二是RegisterEvent注册事件的javascript函数。到这里就差不多接近尾声了,有一些遗憾是对firefox的支持,仅仅是因为firefox不支持disable-output-escaping="yes"的属性,但本例子重点不是兼容性的,所以我也就忽略这些了。
  你可能会说:“哦,原来是这样,没什么了不起啊,我也会”,不过请不要忘记哥伦布发现美洲大陆的例子哦。其实这个例子很简单,没有什么太大的技术难度,重要的是一种思想,一些技巧,还是那句老话,会削木头并不一定能做柜子。
 
 
  效果演示(仅支持IE)
  示例代码下载
  
  

注意:本文为我的独立博客镜像博客,自发表不再更新,原文可能随时被更新,敬请访问原文。同时,请大家不要在此评论,如果有什么看法,请点击这里:http://iove.net/1705/

本文来自http://iove.net,欢迎转载,转载敬请保留相关链接,否则视为侵权,原文链接:http://iove.net/1705/

posted on 2007-07-22 05:40  Conis  阅读(399)  评论(0)    收藏  举报