php 实现无限极分类
原始数据
$array = array( array('id' => 1, 'pid' => 0, 'n' => '河北省'), array('id' => 2, 'pid' => 0, 'n' => '北京市'), array('id' => 3, 'pid' => 1, 'n' => '邯郸市'), array('id' => 4, 'pid' => 2, 'n' => '朝阳区'), array('id' => 5, 'pid' => 2, 'n' => '通州区'), array('id' => 6, 'pid' => 4, 'n' => '望京'), array('id' => 7, 'pid' => 4, 'n' => '酒仙桥'), array('id' => 8, 'pid' => 3, 'n' => '永年区'), array('id' => 9, 'pid' => 1, 'n' => '武安市'), array('id' => 10, 'pid' => 8, 'n' => '永年区镇'), array('id' => 11, 'pid' => 0, 'n' => '上海市') );
生成无限极分类
/** 所有的分类 * @parem $array 数组 * @parem $pid ,最高级别,默认为0,输出从pid 级别的数据 * @parem $level 层级,默认0 * */ function getTree($array, $pid =0, $level = 0){ $f_name=__FUNCTION__; // 定义当前函数名 //声明静态数组,避免递归调用时,多次声明导致数组覆盖 static $list = []; foreach ($array as $key => $value){ //第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点 if ($value['pid'] == $pid){ //父节点为根节点的节点,级别为0,也就是第一级 $flg = str_repeat('|--',$level); // 更新 名称值 $value['n'] = $flg.$value['n']; // 输出 名称 echo $value['n']."<br/>"; //把数组放到list中 $list[] = $value; //把这个节点从数组中移除,减少后续递归消耗 unset($array[$key]); //开始递归,查找父ID为该节点ID的节点,级别则为原级别+1 $f_name($array, $value['id'], $level+1); } } return $list; } // 调用 $list=getTree($array);
调用结果:
河北省 |--邯郸市 |--|--永年区 |--|--|--永年区镇 |--武安市 北京市 |--朝阳区 |--|--望京 |--|--酒仙桥 |--通州区
嵌套标签,前端可以(通过选取子节点)全选、取消全选
function getTree($array, $pid =0, $level = 0){ $f_name=__FUNCTION__; // 定义当前函数名 // 空数组 不在执行 if(empty($array)) return; //声明静态数组,避免递归调用时,多次声明导致数组覆盖 static $html; $html.="<ul>"; foreach ($array as $key => $value){ //第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点 if ($value['pid'] == $pid){ //父节点为根节点的节点,级别为0,也就是第一级 $flg = str_repeat('|--',$level); // 更新 名称值 $value['n'] = $flg.$value['n']; $html.=$temp="<li><input type=\"checkbox\" name=\"limit_id[]\" value='".$value['id']."' >".$value['n']; //把这个节点从数组中移除,减少后续递归消耗 unset($array[$key]); //开始递归,查找父ID为该节点ID的节点,级别则为原级别+1 $vv=$f_name($array, $value['id'], $level+1); // 如果顶级分类下没有一个下级,删除此分类,此步骤可以省略 if(empty($vv) && ($pid<1)) { $html=str_replace($temp,'',$html); } $html.="</li>\r\n"; } } $html.="</ul>\r\n"; // 删除多余的 ul 标签 $html=str_replace("<ul></ul>",'',$html); return $html; }
html 输出结果
<ul> <li><input type="checkbox" name="limit_id[]" value='1'>河北省 <ul> <li><input type="checkbox" name="limit_id[]" value='3'>|--邯郸市 <ul> <li><input type="checkbox" name="limit_id[]" value='8'>|--|--永年区 <ul> <li><input type="checkbox" name="limit_id[]" value='10'>|--|--|--永年区镇 </li> </ul> </li> </ul> </li> <li><input type="checkbox" name="limit_id[]" value='9'>|--武安市 </li> </ul> </li> <li><input type="checkbox" name="limit_id[]" value='2'>北京市 <ul> <li><input type="checkbox" name="limit_id[]" value='4'>|--朝阳区 <ul> <li><input type="checkbox" name="limit_id[]" value='6'>|--|--望京 </li> <li><input type="checkbox" name="limit_id[]" value='7'>|--|--酒仙桥 </li> </ul> </li> <li><input type="checkbox" name="limit_id[]" value='5'>|--通州区 </li> </ul> </li> </li> </ul>
jquery 操作全选
//父级选中 自动选中子级,同时选中自己的父级 $('input[type="checkbox"]').change(function(e) { var checked = $(this).prop("checked"), container = $(this).parent(), siblings = container.siblings(); container.find('input[type="checkbox"]').prop({ indeterminate: false, checked: checked }); function checkSiblings(el) { var parent = el.parent().parent(), all = true; el.siblings().each(function() { return all = ($(this).children('input[type="checkbox"]').prop("checked") === checked); }); if (all && checked) { parent.children('input[type="checkbox"]').prop({ indeterminate: false, checked: checked }); checkSiblings(parent); } else if (all && !checked) { parent.children('input[type="checkbox"]').prop("checked", checked); parent.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0)); checkSiblings(parent); } else { el.parents("li").children('input[type="checkbox"]').prop({ indeterminate: true, checked: false }); } } checkSiblings(container); }); // 父级选中 自动选中子级 /*$("input[type=checkbox]").each(function (i,ele){ let _this=$(this); _this.click(function(){ if(_this.prop('checked')==true) { _this.parent().find('ul input').prop('checked',true); }else { _this.parent().find('ul input').prop('checked',false); } }); });*/
数组嵌套
引用嵌套,php变量默认的传值方式是按指传递,也就是说 假如说 遍历顺序是 河北省 邯郸市 当遍历到河北省时需要把河北省放到tree中,遍历到邯郸市时,需要把邯郸市放到河北省的子节点数组中,所以这里用到了引用传递,当你对河北省做更改时,tree数组中的河北省也一并做了更改
function getTree($list, $pid = 0) { $tree = []; if (!empty($list)) { $newList = []; foreach ($list as $k => $v) { $newList[$v['id']] = $v; } foreach ($newList as $value ) { if ($pid == $value['pid']) { $tree[] = &$newList[$value['id']]; } elseif (isset($newList[$value['pid']])) { $newList[$value['pid']]['items'][] = &$newList[$value['id']]; } } // 如果顶级分类下没有一个下级,删除此分类,此步骤可以省略 foreach ($tree as $k=>$v) { if(!isset($v['items']) && ($pid<1)) unset($tree[$k]); } } return $tree; } // 调用 $list=getTree($array); var_dump($list);
显示结果
array(2) { [0]=> array(4) { ["id"]=> int(1) ["pid"]=> int(0) ["n"]=> string(9) "河北省" ["items"]=> array(2) { [0]=> array(4) { ["id"]=> int(3) ["pid"]=> int(1) ["n"]=> string(9) "邯郸市" ["items"]=> array(1) { [0]=> array(4) { ["id"]=> int(8) ["pid"]=> int(3) ["n"]=> string(9) "永年区" ["items"]=> array(1) { [0]=> array(3) { ["id"]=> int(10) ["pid"]=> int(8) ["n"]=> string(12) "永年区镇" } } } } } [1]=> array(3) { ["id"]=> int(9) ["pid"]=> int(1) ["n"]=> string(9) "武安市" } } } [1]=> array(4) { ["id"]=> int(2) ["pid"]=> int(0) ["n"]=> string(9) "北京市" ["items"]=> array(2) { [0]=> array(4) { ["id"]=> int(4) ["pid"]=> int(2) ["n"]=> string(9) "朝阳区" ["items"]=> array(2) { [0]=> array(3) { ["id"]=> int(6) ["pid"]=> int(4) ["n"]=> string(6) "望京" } [1]=> array(3) { ["id"]=> int(7) ["pid"]=> int(4) ["n"]=> string(9) "酒仙桥" } } } [1]=> array(3) { ["id"]=> int(5) ["pid"]=> int(2) ["n"]=> string(9) "通州区" } } } }
根据子类id查找出所有父级分类信息
/**根据指定id 的查询,所有的父节点 * @parem $id_pid 要查询的id 或者 要查询id的pid;如果传入的是id 包括当前id 值,如果传入id_pid不包括当前id的值 * @parem $array 查分类的数据,在项目使用中此参数可以不传,直接使用sql 查询 * @parem $level 当前id所在层级,默认2 * */ function getParent($id_pid,$array=array(), $level = 2) { $f_name=__FUNCTION__; // 定义当前函数名 static $list=array(); //$array=Db::table('table_name')->where('id',$id_pid)->select(); TP5 foreach($array as $k=>$v) { if($v['id']== $id_pid) { //父级分类id等于所查找的id $flg = str_repeat('|--',$level); // 更新 名称值 $v['n'] = $flg.$v['n']; // 输出 名称 echo $v['n']."<br/>"; $list[]=$v;
// 删除数组
unset($array[$k]); if($v['pid']>=0) { $f_name($v['pid'],$array,$level-1); } } } return $list; } // 调用 getParent(10,$array, $level = 3); echo "<hr/>"; getParent(8,$array, $level = 3);
调用结果显示
getParent(10,$array, $level = 3); |--|--|--永年区镇 |--|--永年区 |--邯郸市 ----------------------------------------- getParent(8,$array, $level = 3); 河北省 |--|--|--永年区 |--|--邯郸市 |--河北省
根据父id获得所有下级子类数
/**根据指定id 查询,所有的子节
* @parem $id 要查询的id
* @parem $array 查分类的数据,在项目使用中此参数可以不传,直接使用sql 查询
* @parem $level 层级,默认1 * */ function getSon($id,$array=array(),$level=1) { $f_name=__FUNCTION__; // 定义当前函数名 static $list; //$array=Db::table('table_name')->where('pid',$id)->select(); TP5 foreach ($array as $k => $v) { if($v['pid'] == $id) { $flg = str_repeat('|--',$level); // 更新 名称值 $v['n'] = $flg.$v['n']; // 输出 名称 echo $v['n']."<br/>"; //存放数组中 $list[] = $v;
// 删除查询过的数组
unset($array[$k]); $f_name($v['id'],$array,$level+1); } } return $list; }
// 调用 $list=$f_name(1,$array);
调用结果:
|--邯郸市 |--|--永年区 |--|--|--永年区镇 |--武安市