最近打算做一个blog,通常每篇文章都有属于自己的分类。下面就记录下我在写blog时实现无限分类的过程。php框架用的是laravel,根据注释也能轻松改成你习惯的框架。
数据表设计
CREATE TABLE `article_category` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父id',`name` char(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类名',`statu` enum('y','n') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'y' COMMENT '是否显示',`created_at` timestamp NULL DEFAULT NULL,`updated_at` timestamp NULL DEFAULT NULL,`remark` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',PRIMARY KEY (`id`),KEY `article_category_pid_index` (`pid`)
) ENGINE=MyISAM AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
程序设计
添加分类
public function addClassify(Request $request)
{// laravel 框架自带的验证机制$this->validate($request,['name' => 'required|unique:article_category','remark' => 'max:100','pid' => 'required|numeric'],['name.required' => '请填写分类名!','name.unique' => '改分类名已存在','remark.max' => '分类简介不能超过100个字符','pid.numeric' => '分类id必须为数字']);// 获取分类名$this->_category->name = $request->input('name');// 获取分类父id,默认是0,为一级分类$this->_category->pid = $request->input('pid',0);// 分类简介$this->_category->remark = $request->input('remark');// 写入数据库$result = $this->_category->save();// 返回结果$result = $result ? '操作成功' : '操作失败';return back()->with('act_msg',$result);
}
获取分类列表
/*** 加载视图* @return [type] [description]*/
public function classify()
{ // 从数据库获取所有分类记录$node = $this->_category->orderBy('id','asc')->get();// 将分类以及子分类整理排序$node = $this->_treeNode($node->toArray(),0);// 加载视图及分配数据return view('admin.classify',['list'=>$node]);
}/*** 整理排序所有分类* @param array $data 从数据库获取的分类* @param integer $parentId 父id,默认一级分类* @return array */
private function _treeNode($data,$parentId = 0)
{// 用于保存整理好的分类节点$node = [];// 循环所有分类foreach ($data as $key => $value) {// 如果当前分类的父id等于要寻找的父id则写入$node数组,并寻找当前分类id下的所有子分类if($parentId == $value ['pid']) {$node [$key] = $value;$node [$key] ['childer'] = $this->_treeNode($data,$value ['id']);}}return $node;
}
方法classify
是用于从数据库获取所有分类以及显示模板。方法_treeNode
是一个递归函数。将从数据库获取的所有分类整理排序。排序好的效果如下图:
渲染视图
<table class="table table-border table-bordered table-bg table-hover table-sort"><thead><tr class="text-c"><th width="25"><input type="checkbox" name="" value=""></th><th width="80">ID</th><!-- <th>标题</th> --><th width="120">分类名</th><th width="80">简介</th><!-- <th width="80">来源</th> --><th width="120">更新时间</th><th width="60">发布状态</th><th width="120">操作</th></tr></thead><tbody><!--遍历数据-->@foreach($list as $val)<tr class="text-c"><td><input type="checkbox" value="" name=""></td><td>{{$val ['id']}}</td><td class="text-l"><u title="查看">{{$val ['name']}}</u></td><td>{{$val ['remark']}}</td><td>{{$val ['updated_at']}}</td><td>@if($val ['statu'] == 'y')<span class="label label-success radius">启用</span> @else <span class="label label-danger radius">禁用</span> @endif</td><td class="f-14 td-manage"><a><i class="Hui-iconfont"></i></a><a><i class="Hui-iconfont"></i></a><a title="删除"><i class="Hui-iconfont"></i></a></td></tr><!--判断该分类下是否有子分类-->@if(!empty($val ['childer'])){{get_childer_node($val ['childer'])}}@endif@endforeach</tbody></table>
渲染视图时需要判断该分类下是否有子分类,如果只做到三级分类,此时只需要再来个二层循环就ok了。这边我自定义了一个递归函数get_childer_node
用于获取该分类下的子分类。具体实现如下:
/*** 获取子节点* @param array $data [description]* @return [type] [description]*/
function get_childer_node($data = [])
{// 记录该分类的深度static $callNum = 1;if(empty($data)) return;foreach ($data as $key => $val) {if($val ['statu'] == 'y')$isShow = '<span class="label label-success radius">启用</span>';else$isShow = '<span class="label label-danger radius">禁用</span>';echo <<<HTML<tr class="text-c"><td><input type="checkbox" value="" name=""></td><td>{$val ['id']}</td><td class="text-l">|----{$val ['name']}</span></td><td>{$val ['remark']}</td><td>{$val ['updated_at']}</td><td>$isShow</td><td><a><i class="Hui-iconfont"></i></a><a><i class="Hui-iconfont"></i></a></td></tr>HTML;// 如果该分类的依旧有子分类则再次遍历输出 if(!empty($val ['childer'])) {$callNum ++;get_childer_node($val ['childer']);}// 重置分类层级$callNum = 1;}
}