Php无限层级并显示层级数
今天在处理递归无限层级菜单时,遇到一个稍微烧脑的问题,如何显示当前节点所在的层级数。
废话不多说,我们先看个直观的无限层级:
<?php
// 这里的arr是直接从数据库取出的,仅作为测试数据
$arr = array(
array('id' => 1, 'name' => '一级菜单a', 'pid' => 0),// pid 父级id
array('id' => 2, 'name' => '一级菜单b', 'pid' => 0),
array('id' => 3, 'name' => '二级菜单a', 'pid' => 1),
array('id' => 4, 'name' => '二级菜单b', 'pid' => 1),
array('id' => 5, 'name' => '二级菜单c', 'pid' => 2),
array('id' => 6, 'name' => '二级菜单d', 'pid' => 2),
array('id' => 7, 'name' => '三级菜单a', 'pid' => 3),
array('id' => 8, 'name' => '三级菜单b', 'pid' => 3),
array('id' => 9, 'name' => '四级菜单a', 'pid' => 8),
); /** 获取所有子节点
* @param $data 所有节点数组
* @param $id $pid 父级节点id
* @param $level 层级
* @return array
*/
function getTree($data, $pid, $level = 0)
{
$list = array();
foreach ($data as $k => $v) {
if ($v['pid'] == $pid) {
$v['level'] = $level;
$v['name'] = $v['name'].'('.($level+1).'级)'; // 这里可以加个层级次数
$v['children'] = getTree($data, $v['id'], $level + 1);
if ($v['children'] == null){
unset($v['children']);
}
$list[] = $v;
}
}
return $list;
} $menu = getTree($arr, 0, 0); $json = json_encode($menu);
?>
<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <style>
*{
box-sizing: border-box;
margin: 0;padding: 0;
}
*:before,*:after{
box-sizing: border-box;
}
ul,
li {
list-style: none;
} .l_tree_container {
width: 100%;
height: 100%;
box-shadow: 0 0 3px #ccc;
margin: 13px;
position: relative;
} .l_tree {
width: calc(100% - 44px);
height: 100%;
padding-left: 42px;
}
.l_tree_branch {
width: 100%;
height: 100%;
display: block;
padding: 13px;
position: relative;
} .l_tree_branch .l_tree_children_btn {
width: 19px;
height: 19px;
background-color: #23b1f0;
font-size: 14px;
text-align: center;
color: #ffffff;
outline: none;
border: 0;
cursor: pointer;
} ul.l_tree:before {
content: '';
border-left: 1px dashed #999999;
height: calc(100%);
position: absolute;
left: 10px;
top: 0px;
} .l_tree .l_tree_branch:last-child::before {
content: '';
width: 3px;
height: calc(100% - 24px);
display: block;
background-color: #ffffff;
position: absolute;
bottom: 0;
left: -34px;
} .l_tree,
.l_tree_branch {
position: relative;
} .l_tree_branch::after {
content: '';
width: 40px;
height: 0;
border-bottom: 1px dashed #000;
position: absolute;
right: calc(100% - 9px);
top: 22px;
} .l_tree_container>.l_tree::before,
.l_tree_container>.l_tree>.l_tree_branch::after {
display: none;
}
</style>
</head> <body> <div id="demo">
<div class="l_tree_container">
<ew-tree :model="testdata"></ew-tree>
</div>
</div> <script>
// 树组件
Vue.component('ew-tree', {
template: `
<ul class="l_tree">
<li class="l_tree_branch" v-for="item in model" :key="item.id">
<div class="l_tree_click">
<button type="button" class="l_tree_children_btn" v-if="item.children" @click="toggle(item)">{{ !item.show ? '-' : '+' }}</button>
<span class="l_folder">{{ item.name }}</span>
</div>
<ew-tree v-show="!item.show" v-if="item.children" :model="item.children"></ew-tree>
</li>
</ul>`,
props: {
model: {}
},
methods: {
toggle: function (item) {
var idx = this.model.indexOf(item)
Vue.set(this.model[idx], 'show', !item.show)
}
}
});
new Vue({
el: "#demo",
data() {
return {
testdata: <?php echo $json?>
}
}
})
</script> </body>
</html>
我们看到所有节点层级数没问题,那么我如何查看节点中pid=3的所有节点层级关系呢
$menu = getTree($arr, 3, 0);
显然不对,况且菜单展示并不友好,pid=3的父节点至少要显示在顶层吧。层级数暂且不管,我们先解决如何显示顶层pid=3的树形结构:
pid=3对应的节点是:二级菜单a。这个可以直接根据数据id查询出来,此处仅做演示哈。调整下代码:
$menu = getTree($arr, 3, 0);
$menu = array(['name' => '二级菜单a','children'=> $menu]);
$json = json_encode($menu);
OK,完美,同样要显示所有pid=1的节点层级关系,一样,pid=1对应的节点是 一级菜单a
$menu = getTree($arr, 1, 0);
$menu = array(['name' => '一级菜单a','children'=> $menu]);
$json = json_encode($menu);
好,回到 刚才的话题,如何正确的显示每个节点所在的层级数呢? 这里我也思考了很久,也没找到快捷的方法。
最终我还是递归的查询本节点所有的父节点id集合:完整代码如下:
<?php
// 这里的arr是直接从数据库取出的,仅作为测试数据
$arr = array(
array('id' => 1, 'name' => '一级菜单a', 'pid' => 0),// pid 父级id
array('id' => 2, 'name' => '一级菜单b', 'pid' => 0),
array('id' => 3, 'name' => '二级菜单a', 'pid' => 1),
array('id' => 4, 'name' => '二级菜单b', 'pid' => 1),
array('id' => 5, 'name' => '二级菜单c', 'pid' => 2),
array('id' => 6, 'name' => '二级菜单d', 'pid' => 2),
array('id' => 7, 'name' => '三级菜单a', 'pid' => 3),
array('id' => 8, 'name' => '三级菜单b', 'pid' => 3),
array('id' => 9, 'name' => '四级菜单a', 'pid' => 8),
); /** 获取所有子节点
* @param $data 所有节点数组
* @param $id $pid 父级节点id
* @param $level 层级
* @return array
*/
function getTree($data, $pid, $level = 0)
{
$list = array();
foreach ($data as $k => $v) {
if ($v['pid'] == $pid) {
$v['level'] = $level;
$v['name'] = $v['name'] . '(' . ($level + 1) . '级)'; // 这里可以加个层级次数
$v['children'] = getTree($data, $v['id'], $level + 1);
if ($v['children'] == null) {
unset($v['children']);
}
$list[] = $v;
}
}
return $list;
} /** 根据子节点获取父节点id
* @param $data 所有节点数组
* @param $id id 主键id
* @return array
*/
function getParentid($data, $id)
{
$arr = array();
foreach ($data as $v) {
if ($v['id'] == $id) {
$arr[] = $v;
//$arr[$v['id']]=$v['name'];
$arr = array_merge(getParentid($data, $v['pid']), $arr);
}
}
return $arr; } $id = 8 ; // 对应的节点是: 三级菜单b 对应的pid 是 3
$pid = 3; // 对应的节点是 二级菜单a $toparr = getParentid($arr, $id); // 节点为8的所有父节点 id: 1 3 8 这里包含了自身,注意剔除 $level = count($toparr); // 节点所在的层级数
$menu = getTree($arr, $pid, $level-1);
if($pid)
$menu = array(['name' => '二级菜单a' . '(' . ($level-1) . '级)', 'children' => $menu]); $json = json_encode($menu);
?>
<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
} *:before, *:after {
box-sizing: border-box;
} ul,
li {
list-style: none;
} .l_tree_container {
width: 100%;
height: 100%;
box-shadow: 0 0 3px #ccc;
margin: 13px;
position: relative;
} .l_tree {
width: calc(100% - 44px);
height: 100%;
padding-left: 42px;
} .l_tree_branch {
width: 100%;
height: 100%;
display: block;
padding: 13px;
position: relative;
} .l_tree_branch .l_tree_children_btn {
width: 19px;
height: 19px;
background-color: #23b1f0;
font-size: 14px;
text-align: center;
color: #ffffff;
outline: none;
border: 0;
cursor: pointer;
} ul.l_tree:before {
content: '';
border-left: 1px dashed #999999;
height: calc(100%);
position: absolute;
left: 10px;
top: 0px;
} .l_tree .l_tree_branch:last-child::before {
content: '';
width: 3px;
height: calc(100% - 24px);
display: block;
background-color: #ffffff;
position: absolute;
bottom: 0;
left: -34px;
} .l_tree,
.l_tree_branch {
position: relative;
} .l_tree_branch::after {
content: '';
width: 40px;
height: 0;
border-bottom: 1px dashed #000;
position: absolute;
right: calc(100% - 9px);
top: 22px;
} .l_tree_container > .l_tree::before,
.l_tree_container > .l_tree > .l_tree_branch::after {
display: none;
}
</style>
</head> <body> <div id="demo">
<div class="l_tree_container">
<ew-tree :model="testdata"></ew-tree>
</div>
</div> <script>
// 树组件
Vue.component('ew-tree', {
template: `
<ul class="l_tree">
<li class="l_tree_branch" v-for="item in model" :key="item.id">
<div class="l_tree_click">
<button type="button" class="l_tree_children_btn" v-if="item.children" @click="toggle(item)">{{ !item.show ? '-' : '+' }}</button>
<span class="l_folder">{{ item.name }}</span>
</div>
<ew-tree v-show="!item.show" v-if="item.children" :model="item.children"></ew-tree>
</li>
</ul>`,
props: {
model: {}
},
methods: {
toggle: function (item) {
var idx = this.model.indexOf(item)
Vue.set(this.model[idx], 'show', !item.show)
}
}
});
new Vue({
el: "#demo",
data() {
return {
testdata: <?php echo $json?>
}
}
})
</script> </body>
</html>
同样要显示所有节点:直接把pid赋值0,比如:
$id = 2 ; // 对应的节点是: 一级菜单b 对应的pid 是 0
$pid = 0; // 对应的节点是 0 为 一级节点 显示所有节点,上面的$id用不到 $toparr = getParentid($arr, $id); // $level = count($toparr); // 节点所在的层级数
$menu = getTree($arr, $pid, $level-1);
if($pid)
$menu = array(['name' => '二级菜单a' . '(' . ($level-1) . '级)', 'children' => $menu]); $json = json_encode($menu);
看起来没毛病,博友们如果有好的办法获取任意一个节点所处的层级数,欢迎拍砖留言哈。
Php无限层级并显示层级数的更多相关文章
- js treeData 树形数据结构 无限层级(转载)
js实现无限层级树形数据结构(创新算法) 转载:https://blog.csdn.net/Mr_JavaScript/article/details/82817177 由于做项目的需要,把一个线性数 ...
- 简单叨叨bootstrap按钮无限层级下拉菜单的实现
0.写在前面的话 最近看书都懈怠了,又正值新项目,虽说并不是忙得不可开交,好吧我老实交待,我就是偷懒了其实,博客也没更.言归正传,对于前端的不熟悉现在确实是个让我头疼的事情,以至于一些功能要在网络上漫 ...
- django 无限层级的评论
一.摘要 拓展 django 官方的评论库,为评论提供无限层级的支持. 二.demo演示 访问链接: https://github.com/zmrenwu/django-mptt-comments 下 ...
- java中实现无限层级的树形结构
本文展示了两个实现方法的代码.两个代码的实现方法不同,代码2更为简单. 先看一下最后实现的结果: 最后结果-json 代码1: 实现过程: 1.传入一段json字符串 2.将字符串转换成对象存入节点列 ...
- Android上的MVP:如何组织显示层的内容
MVP(Model View Presenter)模式是著名的MVC(Model View Controller)模式的一个演化版本,目前它在Android应用开发中越来越重要了,大家也都在讨论关于M ...
- Jquery实现鼠标移到某个对象,弹出显示层。
/** * 鼠标移上去显示层 * @param divId 显示的层ID * @returns */ $.fn.myHoverTip = function(divId) { var div = $(& ...
- SQL查询无限层级结构的所有下级,所有上级
无限层级结构的table1表,Id(主键),ParentId(父级id)查询某个Id的所有下级或所有上级,使用WITH AS,UNION ALL 查询 1.查询Id为1所有的下级 WITH T AS( ...
- 系统管理模块_部门管理_改进_抽取添加与修改JSP页面中的公共代码_在显示层抽取BaseAction_合并Service层与Dao层
系统管理模块_部门管理_改进1:抽取添加与修改JSP页面中的公共代码 commons.jspf <%@ page language="java" import="j ...
- MVC框架显示层——Velocity技术
Velocity,名称字面翻译为:速度.速率.迅速,用在Web开发里,用过的人可能不多,大都基本知道和在使用Struts,到底Velocity和Struts(Taglib和Tiles)是如何联系?在技 ...
随机推荐
- 洛谷 P2684 搞清洁
P2684 搞清洁 题目描述 FJ准备分配它的N只奶牛(1 <= N <= 25,000) 做清洁工作,他把一天分成T(1 <= T <= 1,000,000)个时间段,他希望 ...
- codeforce 571 B Minimization
题意:给出一个序列,经过合适的排序后.使得最小. 做法:将a升序排序后,dp[i][j]:选择i个数量为n/k的集合,选择j个数量为n/k+1的集合的最小值. 举个样例, a={1,2,3,4,5,6 ...
- js---10作用域链
<html> <head> <title>scope basic</title> </head> <body> <scri ...
- Istio Service Mash管理微服务
Istio Service Mash管理微服务 今天的文章通过Istio开源项目展示如何为Kubernetes管理的微服务提供可见性,弹性,安全性和控制. 服务是现代软件体系结构的核心.比起复杂庞大的 ...
- 网络最大流算法—Dinic算法及优化
前置知识 网络最大流入门 前言 Dinic在信息学奥赛中是一种最常用的求网络最大流的算法. 它凭借着思路直观,代码难度小,性能优越等优势,深受广大oier青睐 思想 $Dinic$算法属于增广路算法. ...
- Fragment-Transaction 源码分析
概述 这篇文章的简要分析了Activity中的Transaction和add,replace等操作以及backstack的工作原理. 分析transaction源码的原因是因为我在写一个测试代码的时候 ...
- C++ 补课(二)
1,如果遇到派生类成员和基类成员的名称冲突的情况,程序会采用派生类成员执行相应的操作.如果需要使用基类中的同名成员,则必须在程序中使用全局分辨符“::” 虚基类 —— 派生类在继承基类时加入“virt ...
- Markdown最简单常用的语法
1,文本强调: 文本倾斜,*我是倾斜的文本* 文本加粗,**我是加粗的文本** 文本删除线,~~带删除线的文本~~ 2,链接,分为行内式与参数式,参数式多用于在文章中多次使用相同的链接 行内式写法:[ ...
- 洛谷——P1307 数字反转
https://www.luogu.org/problem/show?pid=1307#sub 题目描述 给定一个整数,请将该数各个位上数字反转得到一个新数.新数也应满足整数的常见形式,即除非给定的原 ...
- POJ 2481 Cows (线段树)
Cows 题目:http://poj.org/problem?id=2481 题意:有N头牛,每仅仅牛有一个值[S,E],假设对于牛i和牛j来说,它们的值满足以下的条件则证明牛i比牛j强壮:Si &l ...