我需要构建一个id如下所示的菜单树,我尝试下面的代码,首先构建一个树,但不返回预期的输出。 任何人都可以帮忙怎么做?
下面是一个如何使用id
排列项目的示例<ul>
<li id = "1">Office</li>
<li id = "2">Home
<ul>
<li id = "2-1">Bed</li>
<li id = "2-2">Pillow</li>
</ul>
</li>
<li id = "3">School
<ul>
<li id = "3-1">Class
<ul>
<li id = "3-1-1">Grade</li>
</ul>
</li>
</ul>
</li>
</ul>
List<Node> _nodes = new List<Node>();
_nodes.Add(new Node() { id = 1, parentid = 0, name = "Office" });
_nodes.Add(new Node() { id = 2, parentid = 0, name = "Home" });
_nodes.Add(new Node() { id = 3, parentid = 2, name = "Bed" });
_nodes.Add(new Node() { id = 4, parentid = 2, name = "Pillow" });
_nodes.Add(new Node() { id = 6, parentid = 0, name = "School" });
_nodes.Add(new Node() { id = 7, parentid = 6, name = "Class" });
_nodes.Add(new Node() { id = 8, parentid = 7, name = "Grade" });
private static string RenderMenu(List<Node> nodes)
{
StringBuilder menu = new StringBuilder();
if (nodes.Count > 0)
{
menu.AppendLine("<ul>");
foreach (Node _n in nodes)
{
menu.AppendLine("<li>");
if (_n.parentid != 0)
menu.AppendLine(RenderMenu(nodes.Where(p => p.parentid == _n.parentid).ToList()));
else
menu.AppendLine(_n.name);
menu.AppendLine("</li>");
}
menu.AppendLine("</ul>");
}
return menu.ToString();
}
答案 0 :(得分:1)
你有一个树形结构,但你把它画成一个普通的结构。
我的意思是,您的foreach (Node _n in nodes)
会产生<li>
与您List<Node>
中的项目一样多的id
。这不是你想要的。
传递List<Node>
代替List
会更合乎逻辑,更方便,因为您不知道哪些项目会被呈现,因此您需要在每个时刻都需要整个id
在下一个子菜单中。
现在关于唯一ID。我建议您使用与List<Node>
中相同的List
s。它更容易,并且保证它们是唯一的(否则,我们根本无法构建菜单)。您需要存储它的完整路径。
有一个很好的选择 - 使用id
作为函数参数传递数组\ Stack<int>
。但是,具有Node
id
的全球public static List<Node> _nodes;
public static Stack<int> _currentPath;
public static string RenderMenu(int id)
{
var currentChildNodes = _nodes.Where(x => x.parentid == id).ToArray();
if (currentChildNodes == 0) return String.Empty; // No children - no submenu!
StringBuilder menu = new StringBuilder();
menu.AppendLine("<ul>");
foreach (var currentChildNode in currentChildNodes)
{
_currentPath.Push(currentChildNode.id);
menu.AppendLine(String.Format("<li id='{0}'>{1}{2}</li>",
String.Join('-', Array.Reverse(_currentPath.ToArray())),
currentChildNode.name,
RenderMenu(currentChildNode.id));
_currentPath.Pop();
// Keep in mind that if currentChildNode does not have child nodes
// then RenderMenu() will return String.Empty and result will be "<li>name</li>"
}
menu.AppendLine("</ul>");
return menu.ToString();
}
// Somewhere in code
RenderMenu(0);
是一个不错的选择。
每次你“输入”一个节点 - 你把它添加到堆栈,每次你“离开”它 - 你删除一个项目。在任何时候,你都有实际的递归路径。
这就是我如何解决这个问题:
int
如果由于某种原因,您需要生成后续的for (int i = 0; i < currentChildNodes.Count; i++) // Convert to for-loop
{
var currentChildNode = currentChildNodes[i];
_currentPath.Push(i + 1); // Change node.id to i
menu.AppendLine(String.Format("<li id='{0}'>{1}{2}</li>",
String.Join('-', _currentPath.ToArray()),
currentChildNode.name,
RenderMenu(currentChildNode.id));
_currentPath.Pop();
// Keep in mind that if currentChildNode does not have child nodes
// then RenderMenu() will return String.Empty and result will be "<li>name</li>"
}
ID,则可以通过以下方式更改循环:
{{1}}
答案 1 :(得分:1)
string menu = OrganizeMenu(_nodes);
private static string OrganizeMenu(List<Node> nodes)
{
menu.Append("<ul>"); // start the List
List<Node> parentNode = nodes.Where(item => item.parentid == 0).ToList(); // Get all Parent Node (Root Node i.e. a Node with parentid = 0)
List<Node> childNode = nodes.Except(parentNode).ToList(); // Get all Child Node (i.e. a Node with parentid != 0)
foreach (var pNode in parentNode) // traverse for each Parent Node and add this to root level
{
menu.Append("<li>");
menu.Append(pNode.name);
GetChilds(nodes, pNode);
menu.Append("</li>");
}
menu.Append("</ul>"); // end the list
return menu.ToString();
}
private static void GetChilds(List<Node> nodes, Node parentNode)
{
List<Node> childs = nodes.Where(item=> item.parentid == parentNode.id).ToList();
foreach (var child in childs)
{
menu.Append("<ul>");
menu.Append(child.name);
GetChilds(nodes, child);
menu.Append("</ul>");
}
}