PHP结合Javascript实现的动态树型菜单

我们经常看到很多网站上有windows的资源管理器一样的树型菜单,对于树型结构的数据分类显示来说,非常的实用。如果想自己实现这一功能,怎么办?实际上方法很多,有的采用以开发控件的形式实行,有的则是用纯javascript来实现的,而下面我们则是以动态网页开发语言PHP结合JavaScript来实现的。
JavaScript部分很简单,主要是实现菜单展开,折叠以及图标的变换,菜单展开的时候用什么图标,折叠的时候又用什么图标。最后就是怎样打开树叶子的链接的URL地址。
而PHP部分则主要模拟HTML的DIV对象,把一个DIV对象看成是树的一个节点,而这个节点又可以有很多字节点,即一个DIV对象中,又可以加入很多子节点DIV对象,每个子节点DIV对象又可以加入很多孙节点,如此反复,既可以得到一棵树型的菜单,最顶层的是跟节点,也就是树干了,然后每个树枝(子节点)上的也可能还有子树枝的节点,这些节点就是树干的子树干,没有子树枝的节点就是树叶子,这就是树的果实(内容)部分了。然后在对每个节点(DIV对象)设置属性和样式值来好对其操作和显示控制。
我们则以一个关系数据表的内容为例,实现了从表到树型菜单的转换。
以下是程序源代码。

<SCRIPT language=javascript>
 <!--
  function showChildren(obj,tab){
   objs = obj.children.tags("DIV");
   if (objs == null || objs.length == 0) {
   
    return;
   }
  
   /*if(img.src == "images/folder.gif")
    img.src = "images/link0.gif";
   else
    img.src = "images/folder.gif";*/
  
   setImage(obj);
   if (objs[0].style.display == "block") {
    len = objs.length;
    for (i = 0; i < len; i++) {
      objs[i].style.display = "none";
    }
   } else {
    len = objs.length;
    for (i = 0; i < len; i++) {
      objs[i].style.display = "block";
    }   }
  }
 
  function setImage(obj) { 
   imgs = obj.all.tags("IMG");

   folderOn = "images/folder.gif";
   folderOff = "images/folder2.gif";
   if (imgs.length > 1) {
    str = imgs[0].src;
    if (imgs[0].src.lastIndexOf(folderOn) != -1) {
     imgs[0].src = folderOff;
    } else {
     imgs[0].src = folderOn;
    }
   } else {
    if (imgs.src.lastIndexOf(folderOn) != -1)
     imgs.src = folderOff;
    else
     imgs.src = folderOn;
   }
  }
  function showURL(obj,url){
   window.open(url);
  }
 -->
</SCRIPT>
<?PHP
 
 function tab($n,$str) {
  $ret = "";
  for ($i = 0; $i < $n; $i++)
   $ret .= $str;
  return $ret;
 }
 //对子节点数组进行排序,其中有子节点的节点优先
 function sortChildren($child1,$child2) {
  $c1 = $child1->hasChildNodes();
  $c2 = $child2->hasChildNodes();
 
  if ($c1) {
   if ($c2) {
    if ($child1->innerText === $child2->innerText)
     return 0;
    else
     return ($child1->innerText > $child2->innerText)?1:-1;
   } else {
    return -1;
   }
  } else {
   if ($c2) {
    return 1;
   } else {
    if ($child1->innerText === $child2->innerText)
     return 0;
    else
     return ($child1->innerText > $child2->innerText)?1:-1;
   }
  }
 
 }
 /************************************************
 * 类名:DIV
 * 模拟HTML的DIV对象的类
 *************************************************/
 class DIV {
  var $innerText;  //<DIV>和</DIV>之间的文本
  var $innerHTML;  //<DIV>和</DIV>之间的包括HTML标记的文本
  var $children;  //子DIV节点类,关键字是innerText
  var $indent;  //树的深度
  var $id;   //id
  var $attributes; //属性
  var $imgLeaf;  //最下层节点(树叶)的图标
  var $url;   //最下层节点(树叶)的URL地址
  var $imgFolderOn; //节点展开是的图标
  var $imgFolderOff;  //节点折叠是的图标
  var $outerHTML;  //从<DIV>开始到</DIV>结束的HTML文本
  var $parent;  //父节点
 
  /*********************************
  * 构造函数
  * 变量初始化
  **********************************/
  function DIV()
     {
      $this->children = array();
   $this->attributes = array();
      $this->setId($this->genID());
      $this->setInnerText($this->genID());
      $this->setIndent(0);
   $this->setImgLeaf("images/link0.gif");
   $this->setImgFolderOn("images/folder.gif");
   $this->setImgFolderOff("images/folder2.gif");
   $this->url = "";
  
     }
 
  /********************************
  * 生成DIV对象的ID值
  *
  *********************************/
  function genID() {
   $abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
   $nLen = strlen($abc);
   $LEN = 20;
   $id = "";
   for ($i = 0; $i < $LEN; $i++) {
    mt_srand((double)microtime()*1000000);     //设定种子
    $randval = mt_rand();         //生成随机值
    if($i == 0)
     $id .= substr($abc,$randval % ($nLen - 10),1);  //第一位设置成英文字母
    else
     $id .= substr($abc,$randval % $nLen,1);
   }
   return $id;
  }

  /********************************
  * 设置叶子节点的图标imgLeaf
  * $value:图标的路径
  *********************************/
  function setImgLeaf($value) {
   $this->imgLeaf = $value;
  }
 
  /********************************
  * 返回叶子节点的图标路径imgLeaf
  * return:叶子节点的图标路径
  *********************************/
  function getImgLeaf() {
   return $this->imgLeaf;
  }
 
  /********************************
  * 设置节点展开的图标的路径imgFolderOn
  * $value:节点展开图标的路径
  *********************************/
  function setImgFolderOn($value) {
   $this->imgFolderOn = $value;
  }
 
  /********************************
  * 返回节点展开图标的路径imgFolderOn
  * return:节点展开图标的路径
  *********************************/
  function getImgFolderOn() {
   return $this->imgFolderOn;
  }
 
  /********************************
  * 设置节点折叠的图标路径imgFolderOff
  * $value:节点折叠的图标路径
  *********************************/
  function setImgFolderOff($value) {
   $this->imgFolderOff = $value;
  }
  /********************************
  * 返回节点折叠是的图标路径imgFolderOff
  * return:节点折叠是的图标路径
  *********************************/
  function getImgFolderOff() {
   return $this->imgFolderOff;
  } 
 
  /********************************
  * 设置innerText
  * $value:DIV对象之间的文本
  *********************************/
  function setInnerText($value) {
   $this->innerText = $value;
  }
 
  /********************************
  * 返回innerText
  * return:DIV对象之间的文本
  *********************************/
  function getInnerText() {
   return $this->innerText;
  }
 
  /********************************
  * 设置父节点
  * $value:父节点对象
  *********************************/
  function setParent($value) {
   $this->parent = $value;
  }
 
  /********************************
  * 返回父节点
  *********************************/
  function getParent() {
   return $this->parent;
  }
 
  /********************************
  * 返回包括属性在内的开始DIV标记的内容
  *
  *********************************/
  function getStartTag() {
   $str = "";
   while(list($name,$value) = each($this->attributes)) {
    $str .= " $name='$value'";
   }
   $str =tab($this->getIndent(),"/t") . "<DIV$str>/r/n";
   return $str;
  }
 
  /********************************
  * 返回结束DIV标记的内容
  *********************************/
  function getEndTag() {
   return tab($this->getIndent(),"/t") . "</DIV>/r/n";
  }
 
  /********************************
  * 设定DIV标记的属性值
  * $name:属性名
  * $value:值
  *********************************/
  function setAttribute($name,$value) {
   $this->attributes[$name] = $value;
  }
 
  /********************************
  * 返回指定属性的值
  * $name:属性名
  * return:属性值
  *********************************/
  function getAttribute($name) {
   return $this->attributes[$name];
  }
 
  /********************************
  * 设置DIV对象的ID
  * $value:ID值
  *********************************/
  function setId($value) {
   $this->setAttribute("id",$value);
  }
 
  /********************************
  * 返回DIV对象的ID值
  * return:ID值
  *********************************/
  function getId() {
   return $this->getAttribute("id");
  }
 
  /********************************
  * 设置父节点跟字节点的缩进值indent
  * $value:缩进值
  *********************************/
  function setIndent($value) {
   $this->indent = $value;
  }
 
  /********************************
  * 返回缩进值indent
  * return:缩进值
  *********************************/
  function getIndent() {
   return $this->indent;
  }
 
  /********************************
  * 判断是否有字节点
  * return:true-有、false-无
  *********************************/
  function hasChildNodes() {
   return (count($this->children) != 0);
  }
 
  /********************************
  * 添加字节点对象
  * $child:字节点对象
  *********************************/
  function insertChild($child) {
   $innerText = $child->getInnerText();
   //判断该字节点是否存在
   $myChild = $this->getChild($child);
  
   if (!isset($myChild)) {//如果不存在的话,作为新节点添加进去
    $this->children[$innerText] = $child;  
    $this->children[$innerText]->setParent($this);
    $this->children[$innerText]->setIndent($this->getIndent() + 1);
   }
   //返回该字节点
   return $this->children[$innerText];
  }
 
  /********************************
  * 返回指定的字节点
  * $child:字节点
  * return:字节点
  *********************************/
  function getChild($child) {
   $innerText = $child->getInnerText();
   return $this->children[$innerText];
  }
 
  /********************************
  * 返回字节点数组
  *********************************/
  function getChildren() {
   return $this->children;
  }
 
  /********************************
  * 设置属性
  * $name:属性名称
  * $value:属性值
  *********************************/
  function isExist($child) {
   $t = $child->getInnerText();
   while(list($id,$myChild) = each($this->children)) {
    $t2 = $myChild->getInnerText();
    if($t === $t2)
     return true;
   }
   return false;
  }
 
  /********************************
  * 比较两个DIV对象的ID值
  * return:true-相等
  *********************************/
  function equal($obj) {
   if (($this->getId() === $obj->getId()) &&
    ($this->getInnerText() === $obj->getInnerText()))
    return true;
   return false;
  }
 
  /*******************************
  * 对字节点数组进行排序
  *******************************/
  function childrenSort() {
   usort($this->children,sortChildren);
  }
 
  /********************************
  * 返回DIV标记之间的HTML文本
  *********************************/
  function getInnerHTML() {
   //获取属性信息
   $indent   = $this->getIndent();
   $myId    = $this->getId();
   $innerText   = $this->getInnerText();
   $imgLeaf   = $this->getImgLeaf();
   $imgFolderOn  = $this->getImgFolderOn();
   $imgFolderOff  = $this->getImgFolderOff();
   //该节点是否有字节点
   if ($this->hasChildNodes()) {
    $this->childrenSort();
    if ($indent > 0)
     $html = tab($indent + 1,"/t") . tab($indent,"&nbsp;&nbsp;&nbsp;") . "<IMG src='$imgFolderOn'><A href='javascript:showChildren($myId,$indent)'>" . $innerText . "</A>/r/n";
    else
     $html = tab($indent + 1,"/t") . tab($indent,"&nbsp;&nbsp;&nbsp;") . "<IMG src='$imgFolderOff'><A href='javascript:showChildren($myId,$indent)'>" . $innerText . "</A>/r/n";
    $children = $this->getChildren();
    while(list($id,$child) = each($children)) {
     if ($indent > 0) {
      $child->setAttribute("style","display:none;");
      $html .= $child->getOuterHTML();
     // $html .= $child->getStartTag() . $child->getInnerHTML() . $child->getEndTag();
     } else {
      $child->setAttribute("style","display:block;");
      $html .= $child->getOuterHTML();
     // $html .= $child->getStartTag() . $child->getInnerHTML() . $child->getEndTag();
     }
    }
   } else {//树叶
    $html = tab($indent + 1,"/t") . tab($indent,"&nbsp;&nbsp;&nbsp;") . "<IMG src='$imgLeaf'><A href='javascript:showURL($myId,/"$this->url/")'>" . $innerText . "</A>/r/n";
   }
   return $html;
  }
 
  /********************************
  * 返回包含DIV标记在内的HTML文本
  *********************************/
  function getOuterHTML() {
   return $this->getStartTag() . $this->getInnerHTML() . $this->getEndTag();
  }
 
 
  function getChildrenHTML() {
   $html = "";
   $this->childrenSort();
   $children = $this->getChildren();
   while(list($id,$child) = each($children)) {
    $html .= $child->getOuterHTML();
   }
   return $html;
  }
 
  /********************************
  * 分割文本的类型$parttern
  * "A;B;C;D;..."转换后→
  *  A→
  *  B→
  *   C→
  *    D→
  *     ...
  *
  *********************************/
  function insertList($parttern,$itemList) {
   $items = split($parttern,$itemList);
   $nCnt = count($items);
   if ($nCnt > 1) {
    $div = new DIV;
    $div->setInnerText($items[0]);
    $list = substr($itemList,strpos($itemList,";") + 1);
    $this->insertChild($div);
    $this->children[$items[0]]->insertList($parttern,$list);
   } else {
    $div = new DIV;
    $div->setInnerText($itemList);
    $this->insertChild($div);
   }
  }
 }
 
 
 
 /****************************************************
 * 这是一个例子。
 * 数据类似对关系数据表的结构。
 ****************************************************/
 $tr = array(
   array("first","second","third","forth"),
   array("first","second","third","fifth"),
   array("first","second","third","sixth"),
   array("first","third","forth","fifth"),
   array("first","third","third","fifth"),
   array("first","forth","third","fifth"),
   array("second","first","first","first"),
   array("second","second","HAHAH","TEST"),
   array("first","OK","first","first"));
  
 $n1 = count($tr);//计算数组的记录数
 $root = new DIV;//树的根
 
 for ($i = 0; $i < $n1; $i++) {
  $td = $tr[$i];
  $n2 = count($td);
  $parent = "";
  $tmp = "";
  for ($j = 0; $j < $n2; $j++) {
// echo "<br> $n2";
   $value = $td[$j];
   $divObj = new DIV;
   $divObj->setInnerText($value);//设置文本
   //添加子节点
   /**********************************
   数组的元素A,B,C,D,...按照下面的形式进行转换
    A→
     B→
      C→
       D→
        ...
   ***********************************/
   if ( $j == 0) {
    $root->insertChild($divObj);
   } else if ($j == 1) {
    $root->children[$td[0]]->insertChild($divObj);
   } else if ($j == 2) {
    $root->children[$td[0]]->children[$td[1]]->insertChild($divObj);
   } else if ($j == 3) {
    $root->children[$td[0]]->children[$td[1]]->children[$td[2]]->insertChild($divObj);
   }
  }
 
 }
 echo count($root->getChildren()) . "<br>";
// echo "/r/n" . $root->getOuterHTML();

 reset($root);
 $root = new DIV;
 for ($i = 0; $i < $n1; $i++) {
  $record = implode(";",$tr[$i]);
  /**********************************
  数组的元素A,B,C,D,...按照下面的形式转换称字符串
  "A;B;C;D;..."     ...
  ***********************************/
  $root->insertList(";",$record);
 }
 $root->insertList(";","sakdfk;ksdkfksa;skdfk;skdflsa;ksadkf;kak;sdfd");
// echo "/r/n" . $root->getOuterHTML();
?>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值