無限極分類,幾乎在每一個網站上都會用到的,所以而重要。php
先來對數據表進行分析css
parent_id:表示當前分類的父id,他是實現無限級分類的關鍵html
無限級分類,主要從兩個方面進行考慮的。數據庫
1.數據庫的設計,表中的parent_id字段。數組
2.在程序的層面上,來完成,使用遞歸。app
咱們只要理解下面這張圖便可瞭解無限極分類的大部份了post
上面的這三表是否能夠變成下面這一張表呢?測試
這樣的話關聯起來是否是更加方便呢?網站
說白了也就是PID就是他的老爸的ID一直到PID爲0這就到了頂級分類ui
添加分類,首先是要載入添加的表單,確保表單的name和字段一致,首先在view裏面建立一個category文件夾在裏面將模版放進去,咱們先來寫add.html的文件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>SHOP 管理中心 - 添加分類 </title> <meta name="robots" content="noindex, nofollow"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" /> <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" /> </head> <body> <h1> <span class="action-span"><a href="index.php?p=admin&c=category&a=index">商品分類</a></span> <span class="action-span1"><a href="index.php?act=main">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 添加分類 </span> <div style="clear:both"></div> </h1> <!-- start add new category form --> <div class="main-div"> <form action="" method="post" name="theForm" enctype="multipart/form-data" onsubmit="return validate()"> <table width="100%" id="general-table"> <tbody> <tr> <td class="label">分類名稱:</td> <td><input type="text" name="cat_name" maxlength="20" value="" size="27"> <font color="red">*</font></td> </tr> <tr> <td class="label">上級分類:</td> <td> <select name="parent_id"> <option value="0">頂級分類</option> <volist name="cats" id='vo'> <option value="{$vo['cat_id']}">{$vo['cat_name']}</option> </volist> </select> </td> </tr> <tr id="measure_unit"> <td class="label">數量單位:</td> <td><input type="text" name="unit" value="" size="12"></td> </tr> <tr> <td class="label">排序:</td> <td><input type="text" name="sort_order" value="50" size="15"></td> </tr> <tr> <td class="label">是否顯示:</td> <td><input type="radio" name="is_show" value="1" checked="true"> 是<input type="radio" name="is_show" value="0"> 否 </td> </tr> <tr> <td class="label">分類描述:</td> <td> <textarea name="cat_desc" rows="6" cols="48"></textarea> </td> </tr> </tbody></table> <div class="button-div"> <input type="submit" value=" 肯定 "> <input type="reset" value=" 重置 "> </div> </form> </div> <div id="footer"> 版權全部 © 2014-2016 奪命雷公狗 - 技術總結 - </div> </div> </body> </html>
這裏完成了後,下一步就是開始寫CategoryController.class.php控制器裏面的add方法了
public function add(){ if(IS_POST){ //分類信息入庫 $data['cat_name'] = I('cat_name'); $data['parent_id'] = I('parent_id',0,'int');//parent_id一般是整型,因此作個小處理 $data['cat_desc'] = I('cat_desc'); $data['unit'] = I('unit');//數量 $data['is_show'] = I('is_show'); $data['sort_order'] = I('sort_order'); $categoryModel = D('category'); if($categoryModel->create($data)){ //驗證經過 if($categoryModel->add()){ //插入成功 $this -> success('分類信息添加成功',U('index'),1); }else{ //插入失敗 $this -> error('分類信息添加失敗'); } }else{ //驗證失敗 $this -> error($categoryModel->getError()); } return; } //載入添加分類頁面 //獲取全部的分類 $cats = M('category')->select(); $this -> assign('cats',$cats); $this -> display(); }
在這的驗證是經過model層裏面進行驗證的,那麼咱們下一步就是在model文件夾裏建立一個CategoryModel.class.php的文件,代碼以下所示
<?php //商品分類模型 namespace Admin\Model; use Think\Model; class CategoryModel extends Model{ //自動驗證 protected $_validate = array( array('cat_name','require','商品名稱不能爲空'), ); }
好像是完成了噢,不過一測試,發現裏面的無限極分類效果是出來了,可是實在很差看,什麼都逼在同個水平線下,那麼咱們的解決方案是經過樹狀方式來進行解決問題
咱們作目錄樹的時候要玩到遞歸,遞歸說白了就是讓他重複幹事情的,給定一個pid,找他的後代節點,找到保存起來。
條件pid等於給定的id。
最終目的要成爲這樣:
先在model層裏面開幹,
<?php //商品分類模型 namespace Admin\Model; use Think\Model; class CategoryModel extends Model{ //自動驗證 protected $_validate = array( array('cat_name','require','商品名稱不能爲空'), ); //定義一個方法,獲取樹狀的分類信息 public function catTree(){ $cats = $this->select(); return $this->tree($cats); } //定義一個方法,對給定的數組,遞歸造成樹 public function tree($arr,$pid=0,$level=0){ static $tree = array(); foreach($arr as $v){ if($v['parent_id']==$pid){ //說明找到,保存 $v['level'] = $level; $tree[] = $v; //繼續找 $this -> tree($arr,$v['cat_id'],$level+1); } } return $tree; } }
而後在控制器下改下他的查詢方式,代碼以下:
public function add(){ if(IS_POST){ //分類信息入庫 $data['cat_name'] = I('cat_name'); $data['parent_id'] = I('parent_id',0,'int');//parent_id一般是整型,因此作個小處理 $data['cat_desc'] = I('cat_desc'); $data['unit'] = I('unit');//數量 $data['is_show'] = I('is_show'); $data['sort_order'] = I('sort_order'); $categoryModel = D('category'); if($categoryModel->create($data)){ //驗證經過 if($categoryModel->add()){ //插入成功 $this -> success('分類信息添加成功',U('index'),1); }else{ //插入失敗 $this -> error('分類信息添加失敗'); } }else{ //驗證失敗 $this -> error($categoryModel->getError()); } return; } //載入添加分類頁面 //獲取全部的分類 $cats = D('category')->catTree(); $this -> assign('cats',$cats); $this -> display(); }
最後在add.html模版下修改下便可
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>SHOP 管理中心 - 添加分類 </title> <meta name="robots" content="noindex, nofollow"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" /> <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" /> </head> <body> <h1> <span class="action-span"><a href="index.php?p=admin&c=category&a=index">商品分類</a></span> <span class="action-span1"><a href="index.php?act=main">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 添加分類 </span> <div style="clear:both"></div> </h1> <!-- start add new category form --> <div class="main-div"> <form action="" method="post" name="theForm" enctype="multipart/form-data" onsubmit="return validate()"> <table width="100%" id="general-table"> <tbody> <tr> <td class="label">分類名稱:</td> <td><input type="text" name="cat_name" maxlength="20" value="" size="27"> <font color="red">*</font></td> </tr> <tr> <td class="label">上級分類:</td> <td> <select name="parent_id"> <option value="0">頂級分類</option> <volist name="cats" id='vo'> <option value="{$vo['cat_id']}">{$vo['level']|str_repeat=" ",###}{$vo['cat_name']}</option> </volist> </select> </td> </tr> <tr id="measure_unit"> <td class="label">數量單位:</td> <td><input type="text" name="unit" value="" size="12"></td> </tr> <tr> <td class="label">排序:</td> <td><input type="text" name="sort_order" value="50" size="15"></td> </tr> <tr> <td class="label">是否顯示:</td> <td><input type="radio" name="is_show" value="1" checked="true"> 是<input type="radio" name="is_show" value="0"> 否 </td> </tr> <tr> <td class="label">分類描述:</td> <td> <textarea name="cat_desc" rows="6" cols="48"></textarea> </td> </tr> </tbody></table> <div class="button-div"> <input type="submit" value=" 肯定 "> <input type="reset" value=" 重置 "> </div> </form> </div> <div id="footer"> 版權全部 © 2014-2016 奪命雷公狗 - 技術總結 - </div> </div> </body> </html>
添加頁完事,那麼下一步就是列表顯示頁了,先寫index方法由於直接賦值剛纔那個過來便可
//顯示分類 public function index(){ $cats = D('category')->catTree(); $this -> assign('cats',$cats); $this -> display(); }
而後在view下的index.html模版裏進行遍歷
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>SHOP 管理中心 - 商品分類 </title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" /> <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" /> </head> <body> <h1> <span class="action-span"><a href="__MODULE__/category/add">添加分類</a></span> <span class="action-span1"><a href="index.php?p=admin&c=index&a=index">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 商品分類 </span> <div style="clear:both"></div> </h1> <form method="post" action="" name="listForm"> <!-- start ad position list --> <div class="list-div" id="listDiv"> <table width="100%" cellspacing="1" cellpadding="2" id="list-table"> <tbody> <tr> <th>分類名稱</th> <th>商品數量</th> <th>數量單位</th> <th>導航欄</th> <th>是否顯示</th> <th>價格分級</th> <th>排序</th> <th>操做</th> </tr> <volist name="cats" id="vo"> <tr align="center" class="0" id="0_1"> <td align="left" class="first-cell"> {$vo['level']|str_repeat=" ",###} <img src="__ADMIN__/images/menu_minus.gif" id="icon_0_1" width="9" height="9" border="0" style="margin-left:0em" onclick="rowClicked(this)"> <span><a href="goods.php?act=list&cat_id=1">{$vo['cat_name']}</a></span> </td> <td width="10%">0</td> <td width="10%"><span onclick="listTable.edit(this, 'edit_measure_unit', 1)" title="點擊修改內容" style="">{$vo['unit']}</span></td> <td width="10%"><img src="__ADMIN__/images/no.gif" onclick="listTable.toggle(this, 'toggle_show_in_nav', 1)"></td> <td width="10%"><img src=" <if condition="$vo['is_show'] eq 1"> __ADMIN__/images/yes.gif" <else /> __ADMIN__/images/no.gif" </if> onclick="listTable.toggle(this, 'toggle_is_show', 1)"></td> <td><span onclick="listTable.edit(this, 'edit_grade', 1)" title="點擊修改內容" style="">5</span></td> <td width="10%" align="right"><span onclick="listTable.edit(this, 'edit_sort_order', 1)" title="點擊修改內容" style="">{$vo['sort_order']}</span></td> <td width="24%" align="center"> <a href="category.php?act=move&cat_id=1">轉移商品</a> | <a href="__CONTROLLER__/edit/id/{$vo['cat_id']}">編輯</a> | <a href="__CONTROLLER__/del/id/{$vo['cat_id']}" onclick="return confirm('您是否真的刪除這個品牌呢?')" title="移除">移除</a> </td> </tr> </volist> </tbody> </table> </div> </form> </table> </div> </form> <div id="footer"> 版權全部 © 2014-2016 奪命雷公狗 - 技術總結 - </div> </div> <script> /** * 摺疊分類列表 */ var imgPlus = new Image(); imgPlus.src = "application/views/admin/images/menu_plus.gif"; function rowClicked(obj) { // 當前圖像 img = obj; // 取得上二級tr>td>img對象 obj = obj.parentNode.parentNode; // 整個分類列表表格 var tbl = document.getElementById("list-table"); // 當前分類級別 var lvl = parseInt(obj.className); // 是否找到元素 var fnd = false; var sub_display = img.src.indexOf('menu_minus.gif') > 0 ? 'none' : 'table-row' ; // 遍歷全部的分類 for (i = 0; i < tbl.rows.length; i++) { var row = tbl.rows[i]; if (row == obj) { // 找到當前行 fnd = true; //document.getElementById('result').innerHTML += 'Find row at ' + i +"<br/>"; } else { if (fnd == true) { var cur = parseInt(row.className); var icon = 'icon_' + row.id; if (cur > lvl) { row.style.display = sub_display; if (sub_display != 'none') { var iconimg = document.getElementById(icon); iconimg.src = iconimg.src.replace('plus.gif', 'minus.gif'); } } else { fnd = false; break; } } } } for (i = 0; i < obj.cells[0].childNodes.length; i++) { var imgObj = obj.cells[0].childNodes[i]; if (imgObj.tagName == "IMG" && imgObj.src != 'application/views/admin/images/menu_arrow.gif') { imgObj.src = (imgObj.src == imgPlus.src) ? 'application/views/admin/images/menu_minus.gif' : imgPlus.src; } } } </script> </body> </html>
效果以下圖所示:
顯示列表也有了,那麼下一步就開始寫更新頁了
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>SHOP 管理中心 - 添加分類 </title> <meta name="robots" content="noindex, nofollow"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" /> <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" /> </head> <body> <h1> <span class="action-span"><a href="index.php?p=admin&c=category&a=index">商品分類</a></span> <span class="action-span1"><a href="index.php?act=main">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 添加分類 </span> <div style="clear:both"></div> </h1> <!-- start add new category form --> <div class="main-div"> <form action="category.php" method="post" name="theForm" enctype="multipart/form-data" onsubmit="return validate()"> <table width="100%" id="general-table"> <tbody> <tr> <td class="label">分類名稱:</td> <td><input type="text" name="cat_name" maxlength="20" value="{$cat['cat_name']}" size="27"> <font color="red">*</font></td> </tr> <tr> <td class="label">上級分類:</td> <td> <select name="parent_id"> <option value="0">頂級分類</option> <volist name="cats" id='vo'> <option value="{$vo['cat_id']}" <if condition="$vo['cat_id'] eq $cat['parent_id']" >selected="selected"</if> >{$vo['level']|str_repeat=" ",###}{$vo['cat_name']}</option> </volist> </select> </td> </tr> <tr id="measure_unit"> <td class="label">數量單位:</td> <td><input type="text" name="unit" value="{$cat['unit']}" size="12"></td> </tr> <tr> <td class="label">排序:</td> <td><input type="text" name="sort_order" value="{$cat['sort_order']}" size="15"></td> </tr> <tr> <td class="label">是否顯示:</td> <td><input type="radio" name="is_show" value="1" checked="true" <if condition="$cat['is_show'] eq 1">checked="checked"</if> > 是<input type="radio" name="is_show" value="0" <if condition="$cat['is_show'] eq 0">checked="checked"</if> > 否 </td> </tr> <tr> <td class="label">是否顯示在導航欄:</td> <td><input type="radio" name="show_in_nav" value="1"> 是 <input type="radio" name="show_in_nav" value="0" checked="true"> 否 </td> </tr> <tr> <td class="label">設置爲首頁推薦:</td> <td> <input type="checkbox" name="cat_recommend[]" value="1"> 精品 <input type="checkbox" name="cat_recommend[]" value="2"> 最新 <input type="checkbox" name="cat_recommend[]" value="3"> 熱門 </td> </tr> <tr> <td class="label">分類描述:</td> <td> <textarea name="cat_desc" rows="6" cols="48">{$cat['cat_desc']}</textarea> </td> </tr> </tbody></table> <div class="button-div"> <input type="submit" value=" 肯定 "> <input type="reset" value=" 重置 "> </div> <input type="hidden" name="cat_id" value="{$cat['cat_id']}" /> </form> </div> <div id="footer"> 版權全部 © 2014-2016 奪命雷公狗 - 技術總結 - </div> </div> </body> </html>
要注意,在編輯的表單中必定要傳cat_id,不然更新會失敗
<input type="hidden" name="cat_id" value="{$cat['cat_id']}" />
注意:在更新的時候,若是把當前分類或則其子分類做爲上級分類,就會出現邏輯錯誤..
因此咱們要先到model裏面定義一個方法,讓他不能隨便讓他的當前分類或者子分類做爲上級分類,不然就會出現邏輯上的錯誤。。
在CategoryModel.class.php裏面定義一個方法,代碼以下所示:
//給定一個分類,找其後代分類的cat_id,包括他本身 public function getSubIds($cat_id){ $cats = $this -> select(); $list = $this -> tree($cats,$cat_id); $res = array(); foreach($list as $v){ $res[] = $v['cat_id']; } //把cat_id追加到數組 $res[] = $cat_id; return $res; }
讓後會控制器下定義edit方法,代碼以下所示:
//修改分類 public function edit(){ $cat_id = I('id'); if(IS_POST){ //更新分類 $data['cat_name'] = I('cat_name'); $data['parent_id'] = I('parent_id',0,'int');//parent_id一般是整型,因此作個小處理 $data['cat_desc'] = I('cat_desc'); $data['unit'] = I('unit');//數量 $data['is_show'] = I('is_show'); $data['sort_order'] = I('sort_order'); $data['cat_id'] = I('cat_id'); $categoryModel = D('category'); $ids = $categoryModel->getSubIds($data['cat_id']); if(in_array($data['parent_id'],$ids)){ $this -> error('抱歉,不能把當前分類及其子分類做爲其上級分類'); } if($categoryModel->create($data)){ //驗證經過 if($categoryModel->save()){ //插入成功 $this -> success('分類信息修改爲功',U('index'),1); }else{ //插入失敗 $this -> error('分類信息修改失敗'); } }else{ //驗證失敗 $this -> error($categoryModel->getError()); } return; } $cat = M('category')->find($cat_id); $cats = D('category')->catTree(); $this -> assign('cats',$cats); $this -> assign('cat',$cat); $this -> display(); }
修改也好了,那麼就差最後一步了,還差刪除分類的了,代碼以下所示:
//刪除分類 public function del(){ $cat_id = I('id',0,'int'); $categoryModel = D('category'); $ids = $categoryModel->getSubIds($cat_id);//這裏的目的就是查下有沒有子類 if(count($ids)>1){ $this ->error("該分類下面還存在子分類,請處理好了再來"); } if(M('category')->delete($cat_id)){ $this -> success('刪除成功',U('index'),1); }else{ $this ->error('刪除失敗'); } }