Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用PHP和SQL创建“多维树菜单”?_Php_Html_Css_Sql - Fatal编程技术网

如何使用PHP和SQL创建“多维树菜单”?

如何使用PHP和SQL创建“多维树菜单”?,php,html,css,sql,Php,Html,Css,Sql,我搜索了一会儿,但在谷歌和其他论坛上找不到任何东西。但这很奇怪,因为这是我们大学里很受欢迎的任务。所以我认为这篇文章也可以帮助其他人解决同样的问题 我有一个任务: 创建多维树菜单深度未定义,可以是4或7,取决于用户的意愿,应该有添加新元素、编辑、删除和显示整个树结构等选项。使用PHP、SQL和最小CSS 树的可视示例: +Menu +Shop +Tshirts +Yellow +Green +Pants

我搜索了一会儿,但在谷歌和其他论坛上找不到任何东西。但这很奇怪,因为这是我们大学里很受欢迎的任务。所以我认为这篇文章也可以帮助其他人解决同样的问题

我有一个任务:

创建多维树菜单深度未定义,可以是4或7,取决于用户的意愿,应该有添加新元素、编辑、删除和显示整个树结构等选项。使用PHP、SQL和最小CSS

树的可视示例:

+Menu
    +Shop
        +Tshirts
            +Yellow
            +Green
        +Pants
    +Forum
        +Ideas
正如你所看到的,它有4个深度等级:菜单->商店->T恤->黄色 但我必须这样做,用户可以添加任意多的级别和元素

有什么例子吗?我应该使用什么样的SQL结构?
谢谢大家!

我建议MySQL采用以下结构:

I_ID唯一、自动递增、项目名称、项目父ID、子项

子项可能包含该特定项的每个“子项”的I_ID的base64编码、序列化PHP数组

root元素的父ID为root或-1或其他,因此要从数据库中检索该ID,您首先要选择父ID为root或-1或其他任何选项。这是武断的

然后,使用PHP对子数组进行解码,并从系统中选择每个ID

重复上述步骤,直到不再有孩子。递归函数在这里可以很好地为您服务


当您将每一行添加到DOM中时,给它们一个特定的类,使它们隐藏起来。单击+时,使用javascript将该元素的所有子元素更改为具有一个不隐藏的类,并将刚刚单击的+按钮替换为-按钮。类似地处理减号按钮。

解决方案非常简单:

SQL结构 表格菜单项int id、varchar title、varchar link、int level、bool是父项

您可以添加附加链接、颜色等选项

默认级别为1。 默认值为_parent=false

之后,继续将条目输入数据库。如果项有子项-is_parent=true,并且所有子项都有父项级别的+1级

在输出中,只需添加任何新级别项目缩进的格式。 另外,如果项目的链接是页面的当前URL,则突出显示该项目为活动


仅此而已。

您希望使用ID和parentID保存数据库中的每个元素,如果不存在这样的父元素,则该ID和parentID可以为null。PHP是您最大的问题,但在这里,引用是您将平面结构转换为树结构的好朋友

考虑以下DB结果:

----------------------------
| id | parentID | text     |
|----|----------|----------|
| 1  | null     | Item #1  |
| 2  | 5        | Item #2  |
| 3  | 2        | Item #3  |
| 4  | 2        | Item #4  |
| 5  | null     | Item #5  |
| 6  | 5        | Item #6  |
| 7  | 3        | Item #7  |
| 8  | 5        | Item #8  |
| 9  | 1        | Item #9  |
| 10 | 7        | Item #10 |
----------------------------
考虑以下可能来自DB结果的数组-尽管ID是键很重要。您可以简单地将DB结果转换为以下内容—唯一需要的键是parentID:

$menu = array(
    1 => array('text' => 'Item #1', 'parentID' => null),
    2 => array('text' => 'Item #2', 'parentID' => 5),
    3 => array('text' => 'Item #3', 'parentID' => 2),
    4 => array('text' => 'Item #4', 'parentID' => 2),
    5 => array('text' => 'Item #5', 'parentID' => null),
    6 => array('text' => 'Item #6', 'parentID' => 5),
    7 => array('text' => 'Item #7', 'parentID' => 3),
    8 => array('text' => 'Item #8', 'parentID' => 5),
    9 => array('text' => 'Item #9', 'parentID' => 1),
   10 => array('text' => 'Item #10', 'parentID' => 7),
);
并将其转化为树状结构:

<?php    
$addedAsChildren = array();

foreach ($menu as $id => &$menuItem) { // note that we use a reference so we don't duplicate the array
    if (!empty($menuItem['parentID'])) {
        $addedAsChildren[] = $id; // it should be removed from root, but we'll do that later

        if (!isset($menu[$menuItem['parentID']]['children'])) {
            $menu[$menuItem['parentID']]['children'] = array($id => &$menuItem); // & means we use the REFERENCE
        } else {
            $menu[$menuItem['parentID']]['children'][$id] = &$menuItem; // & means we use the REFERENCE
        }
    }

    unset($menuItem['parentID']); // we don't need parentID any more
}

unset($menuItem); // unset the reference

foreach ($addedAsChildren as $itemID) {
    unset($menu[$itemID]); // remove it from root so it's only in the ['children'] subarray
}
导致:

<ul><li>Item #1<ul><li>Item #9</li></ul></li><li>Item #5<ul><li>Item #2<ul><li>Item #3<ul><li>Item #7<ul><li>Item #10</li></ul></li></ul></li><li>Item #4</li></ul></li><li>Item #6</li><li>Item #8</li></ul></li></ul>
…并呈现:


下面是我的链接目录脚本的类别表中的代码,它完成了您要查找的内容:

数据库设计:

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
  `parent` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
)
要使用PHP在破折号中打印它们,请执行以下操作:

function parse($tree,$parent = 0,$level = 0){
    $level++;
    foreach ($tree as $p)  {
        if ($p['parent'] != $parent) continue;
        $p['name'] = str_repeat('-',$level-1) . $p['name'];
        echo "<option name='cat' value='{$p['id']}'>{$p['name']}</option>";
        parse ($tree, $p['id'],$level);
    }
}

    $q = $link->query("SELECT * FROM `categories` ORDER BY name ASC");
    $cats = array();
    while($row = $q->fetch()){
        $cats[] = array("id"=>$row['id'],"name"=>$row['name'],"parent"=>$row['parent'],"level"=>0);
    }

parse($cats)

如果使用$level参数而不是破折号作为输出,则可以删除该参数。

请看这篇文章:那么我的数据库中需要多少表来完成此操作?它如何知道哪个是父母,哪个是孩子?你能在代码中加些注释吗?我有点困惑。谢谢大家!@Ignas只有一个表,每个菜单项有一行。id是项的id,parentID是父菜单项的id。IKt正在工作,但它如何知道谁是谁的孩子?你能解释一下这行吗:$meniu[$meniuItem['parentID']]['children']-你从哪里得到的['children']?@Ignas$menu[$menuItem['parentID']]将是父$menuItem如果parentID是5,这等于$menu[5]。这里我们首先检查它是否有儿童密钥?如果没有,我们将创建它,但是如果它已经有一个子键,那么我们只需将项添加到该数组中。哦,我明白了,稍后在我们决定谁是父项之后,我们将取消设置它,对吗?
function parse($tree,$parent = 0,$level = 0){
    $level++;
    foreach ($tree as $p)  {
        if ($p['parent'] != $parent) continue;
        $p['name'] = str_repeat('-',$level-1) . $p['name'];
        echo "<option name='cat' value='{$p['id']}'>{$p['name']}</option>";
        parse ($tree, $p['id'],$level);
    }
}

    $q = $link->query("SELECT * FROM `categories` ORDER BY name ASC");
    $cats = array();
    while($row = $q->fetch()){
        $cats[] = array("id"=>$row['id'],"name"=>$row['name'],"parent"=>$row['parent'],"level"=>0);
    }

parse($cats)