龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > php编程 >

无限分级和树状节点输出

时间:2014-07-22 14:49来源: 作者: 点击:
分享到:
传入简单的原始数据,可以得出节点间的N种关系,并能输出树状的DOM注意:请参考git.oschina.net上的最新代码(点源码出处链接)
传入简单的原始数据,可以得出节点间的N种关系,并能输出树状的DOM
注意:请参考git.oschina.net上的最新代码(点"源码出处"链接)
<?php
/**
 * 输出无限分类,我自己写的哦~
 * 
 * @author binny_w@qq.com
 * @since 2013-09-24 AM
 */
/* 使用示例 */
/*
$arrAll = array(
    array('id' => 1, 'name' => '栏目分类_1', 'name_en' => 'cat_1', 'parent_id' => 0),
    array('id' => 2, 'name' => '栏目分类_2', 'name_en' => 'cat_2', 'parent_id' => 0),
    array('id' => 3, 'name' => '栏目分类_3', 'name_en' => 'cat_3', 'parent_id' => 1),
    array('id' => 4, 'name' => '栏目分类_4', 'name_en' => 'cat_4', 'parent_id' => 1),
    array('id' => 5, 'name' => '栏目分类_5', 'name_en' => 'cat_5', 'parent_id' => 2),
    array('id' => 6, 'name' => '栏目分类_6', 'name_en' => 'cat_6', 'parent_id' => 4),
    array('id' => 7, 'name' => '栏目分类_7', 'name_en' => 'cat_7', 'parent_id' => 6),
    array('id' => 8, 'name' => '栏目分类_8', 'name_en' => 'cat_8', 'parent_id' => 7),
    array('id' => 9, 'name' => '栏目分类_9', 'name_en' => 'cat_9', 'parent_id' => 6)
);
$objT = new TreeList($arrAll);
print_r($objT->arrAll);
print_r($objT->arrIdAll);
print_r($objT->arrIdChildren);
print_r($objT->arrIdSon);
print_r($objT->arrIdLeaf);
print_r($objT->arrIdRelation);
print_r($objT->arrIdRelationSimple);
print_r($objT->arrIdRoot);
print_r($objT->arrIdBackPath);
print($objT->getTable());
print($objT->getSelect('cat', array(1, 8), true));
*/
// !defined('IN_FRAME') && die('404 Page');
class TreeList {
    
    /**
     * 分析出所有可能用到的数据
     */
    public $arrAll = array(); // 原始数据
    public $arrIdRelation = array(); // 按_ID作键名的多维关系
    public $arrIdRelationSimple = array(); //  按_ID作键名的多维关系的简化,用来输出树状图
    public $arrIdAll = array(); // 将原始数据转化成的_ID作键名的数组
    public $arrIdSon = array(); // 所有的父子关系
    public $arrIdLeaf = array(); // 叶子节点的_ID
    public $arrIdRoot = array(); // 根节点的_ID
    public $arrIdChildren = array(); // 每个节点下的子孙后代_ID
    public $arrIdBackPath = array(); // 每个节点回逆到根
    public $strItem = '<br />{$strSep}{$name}'; // 输出树的结构
    
    /**
     * 构造函数,传入原始数据
     */
    public function __construct($arrData) {
        $this->arrAll = $arrData;
        $this->processData();
    }
    
    /**
     * 简单的树
     */
    public function getHtml() {
        return $this->genHtml();
    }
    
    /**
     * 用Table来画树
     */
    public function getTable() {
        $this->strItem = '<tr><td>{$strSep}{$name}</td><td align=\"center\">{$name}</td><td align=\"center\">{$name_en}</td></tr>';
        $strRe = '<table border="1" width="50%">';
        $strRe .= '<tr><th width="30%">结构</th><th width="20%">中文名</th><th width="10%">英文名</th></tr>';
        $strRe .= $this->genHtml();
        $strRe .= '</table>';
        return $strRe;
    }
    
    /**
     * 在下拉框中显示
     * example:
     * $objTreeList->getSelect('parent_id', 0, false, 'class="span5"', array(0, '≡ 作为一级栏目 ≡')))
     */
    public function getSelect($strName = 'tree', $arrValue = array(), $blmMulti = false, $strExt = '', $arrFirst = null) {
        !is_array($arrValue) && $arrValue = array($arrValue);
        foreach ($this->arrIdAll as $strTemp => $arrTemp) {
            $this->arrIdAll[$strTemp]['selected'] = '';
            if (in_array($arrTemp['id'], $arrValue)) {
                $this->arrIdAll[$strTemp]['selected'] = ' selected="selected"';
            }
        }
        $this->strItem = '<option value=\"{$id}\"{$selected} title=\"{$name_en}\">{$strSep}{$name}</option>';
        $strRe = '<select id="id_' . $strName . '" name="' . $strName . ($blmMulti ? '[]' : '') . '"';
        $strRe .= ($blmMulti ? ' multiple="multiple"' : '') . (empty($strExt) ? '' : ' ' . $strExt) . '>';
        if (is_array($arrFirst) && count($arrFirst) == 2) {
            $strRe .= '<option value="' . $arrFirst[0] . '">' . $arrFirst[1] . '</option>';
        }
        $strRe .= $this->getHtml() . '</select>';
        return $strRe;
    }
    
    /* ----- 以下的都是处理数据的私有函数,递归和循环之类,很复杂! ----- */
    private function helpForGetRelation($arrData) {
        $arrRe = array();
        foreach ($arrData as $strTemp => $arrTemp) {
            $arrRe[$strTemp] = $arrTemp;
            if (isset($this->arrIdRelation[$strTemp])) {
                $arrRe[$strTemp] = $this->arrIdRelation[$strTemp];
            }
            if (count($arrRe[$strTemp]) > 0) {
                $arrRe[$strTemp] = $this->helpForGetRelation($arrRe[$strTemp]);
            } else {
                array_push($this->arrIdLeaf, $strTemp);
            }
        }
        return $arrRe;
    }
    
    private function helpForGetChildren($arrData) {
        $arrRe = array_keys($arrData);
        foreach ($arrData as $arrTemp) {
            $arrRe = array_merge($arrRe, $this->helpForGetChildren($arrTemp));
        }
        return $arrRe;
    }
    
    private function helpForGetBackPath($str) {
        $arrRe = array();
        $intTemp = $this->arrIdAll[$str]['parent_id'];
        if ($intTemp > 0) {
            $intTemp = '_' . $intTemp;
            array_push($arrRe, $intTemp);
            $arrRe = array_merge($arrRe, $this->helpForGetBackPath($intTemp));
        }
        return $arrRe;
    }
    
    private function processData() {
        foreach ($this->arrAll as $arrTemp) {
            $strTemp = '_' . $arrTemp['id'];
            $this->arrIdAll[$strTemp] = $arrTemp;
            if ($arrTemp['parent_id'] > 0) {
                $strTemp_ = '_' . $arrTemp['parent_id'];
                !isset($this->arrIdRelation[$strTemp_]) && $this->arrIdRelation[$strTemp_] = array();
                $this->arrIdRelation[$strTemp_][$strTemp] = array();
                !isset($this->arrIdSon[$strTemp_]) && $this->arrIdSon[$strTemp_] = array();
                array_push($this->arrIdSon[$strTemp_], $strTemp);
            } else {
                !isset($this->arrIdRelation[$strTemp]) && $this->arrIdRelation[$strTemp] = array();
                array_push($this->arrIdRoot, $strTemp);
            }
        }
        $this->arrIdRelation = $this->helpForGetRelation($this->arrIdRelation);
        $this->arrIdLeaf = array_unique($this->arrIdLeaf);
        foreach ($this->arrIdRelation as $strTemp => $arrTemp) {
            $this->arrIdChildren[$strTemp] = $this->helpForGetChildren($arrTemp);
            in_array($strTemp, $this->arrIdRoot) && $this->arrIdRelationSimple[$strTemp] = $arrTemp;
        }
        $arrTemp = array_keys($this->arrIdAll);
        foreach ($arrTemp as $strTemp) {
            $this->arrIdBackPath[$strTemp] = $this->helpForGetBackPath($strTemp);
        }
    }
    
    private function genSeparator($intLen) {
        $strRe = '';
        $i = 0;
        while ($i < $intLen) {
            $strRe .= ' ' . (($i + 1 == $intLen) ? '├' : '│');
            $i ++;
        }
        !empty($strRe) && $strRe .= '─';
        return $strRe;
    }
    
    private function genHtml($arrRelation = null, $intSep = 0) {
        $strRe = '';
        null === $arrRelation && $arrRelation = $this->arrIdRelationSimple;
        foreach ($arrRelation as $strKey => $arrTemp) {
            if (count($this->arrIdAll[$strKey]) > 0) {
                $strSep = $this->genSeparator($intSep);
                extract($this->arrIdAll[$strKey]);
                eval('$strRe .= "' . $this->strItem . '";');
                count($arrTemp) > 0 && $strRe .= $this->genHtml($arrTemp, ($intSep + 1));
            }
        }
        return $strRe;
    }
}
精彩图集

赞助商链接