關於無限極分類,通過父ID或全路徑的不同寫法與簡單分析說明

逍遙俠發表於2018-10-29

#在日常的專案中,我們常常會接觸到無限極分類。一般情況下無限極分類有兩種實現的方式。第一種方式是通過資料表中的父ID。從而去一層一層地往上找。第二種方式是通過記錄分類的全路徑進行實現。接下來我將會根據兩種不同的方法,通過編寫小案例讓您可以更快的理解和熟悉無限極分類。

#本次的程式碼案例實現是基於laravelDB運算元據庫。因此這裡呼叫的是直接的資料模型去獲取資料。但是其實現的原理適用於各個框架與平臺。


1.基於通過父級ID獲取對應的無限極分類方法。

1.首先我們展示一下資料庫的說明與建立

CREATE TABLE `deepcate` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pid` int(11) DEFAULT NULL,
  `catename` varchar(11) DEFAULT NULL,
  `cateorder` int(11) DEFAULT NULL COMMENT '排序欄位',
  `createtime` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

#分類表中 我們需要注意,我們要為對應的分類建立一個pid欄位用於儲存資料的上級ID複製程式碼

2.為我們的資料表新增適當的測試資料

INSERT INTO `deepcate` VALUES (1,0,'新聞',0,0),(2,0,'圖片',0,0),(3,1,'國內新聞',0,0),(4,1,'國外新聞',0,0),(5,2,'風景圖片',0,0),(6,2,'美女圖片',0,0),(7,4,'美國新聞',0,0),(8,3,'廣東新聞',0,0),(9,5,'海灘風景',0,0),(10,6,'模特風采',0,0);
複製程式碼

案例:1

編寫獲通過父ID方式取無限極分類列表的方法

程式設計思路:

1.獲取所有的分類資訊,並指定預設的頂級分類ID

2.遍歷迴圈傳入的資料,並判斷當前的資料是否屬於傳入的頂級ID

3.如果判斷為真則利用遞迴特性判斷當前的資料中是否存在下級

4.如果完成判斷,則返回輸出的資料

//首先我們獲取分類資訊表中的所有資料並儲存到變數$data$data=DB::table('deepcate')->get()->toarray();


//編寫獲取分類樹的方法
/**
 * 作者:逍遙俠
 * 建立時間:2018/10/29
 * @param int $pid 父級ID
 * @param $data    傳入的資料
 * @param $level   當前的等級結構
 * @return array   返回資料
 */
public function get_tree($pid=0,$data,$level){
    //定義靜態的陣列存放變數
    static $arr=[];
    //遍歷資料
    foreach ($data as $k=>$v){
        //判斷當前遍歷的資料的父級是否為傳入的pid
        if($v->pid==$pid){;
            $arr[$k]['name']=$v->catename;
            $arr[$k]['id']=$v->id;
            $arr[$k]['level']=$level;
            //判斷當前資料中是否存在子分類,並給對應的結果+1
            $this->get_tree($v->id,$data,$level+1);
        }
    }
    return $arr;
}
#執行的結果
array:10 [▼
  0 => array:3 [▼
    "name" => "新聞"
    "id" => 1
    "level" => 0
  ]
  2 => array:3 [▼
    "name" => "國內新聞"
    "id" => 3
    "level" => 1
  ]
  7 => array:3 [▼
    "name" => "廣東新聞"
    "id" => 8
    "level" => 2
  ]
  3 => array:3 [▼
    "name" => "國外新聞"
    "id" => 4
    "level" => 1
  ]
  6 => array:3 [▼
    "name" => "美國新聞"
    "id" => 7
    "level" => 2
  ]
  1 => array:3 [▼
    "name" => "圖片"
    "id" => 2
    "level" => 0
  ]
  4 => array:3 [▼
    "name" => "風景圖片"
    "id" => 5
    "level" => 1
  ]
  8 => array:3 [▼
    "name" => "海灘風景"
    "id" => 9
    "level" => 2
  ]
  5 => array:3 [▼
    "name" => "美女圖片"
    "id" => 6
    "level" => 1
  ]
  9 => array:3 [▼
    "name" => "模特風采"
    "id" => 10
    "level" => 2
  ]
]複製程式碼

案例:2

編寫通過父ID方式獲取麵包屑導航

程式設計思路:

1.通過傳入的ID獲取對應的資料

2.判斷資料是否為真,如果為真則儲存對應需要的變數值,利用遞迴特性,傳入該資料中的父級ID繼續獲取資料

//獲取麵包屑導航
$bread=$this->get_bread(10);
/**
 * 作者:逍遙俠
 * 建立時間:2018/10/29
 * @param $id 傳入的對應ID
 * @return array 
 */
public function get_bread($id){
     //定義靜態的陣列存放變數
    static $arr=[];
    //根據傳入的ID獲取對應的分類資訊
    $res=DB::table('deepcate')->find($id);
    //判斷能否獲取資料
    if($res){
        $data['name']=$res->catename;
        $data['id']=$res->id;
        array_push($arr,$data);
        //傳入該資料的父級ID作為查詢元素判斷是否存在
        $this->get_bread($res->pid);
    }
    //重新排序
    krsort($arr);
    return $arr;

}

#執行結果
array:3 [▼
  2 => array:2 [▼
    "name" => "圖片"
    "id" => 2
  ]
  1 => array:2 [▼
    "name" => "美女圖片"
    "id" => 6
  ]
  0 => array:2 [▼
    "name" => "模特風采"
    "id" => 10
  ]
]
複製程式碼


2.基於全路徑模式獲取對應的無限極分類方法

1.首先我們展示一下資料庫的說明與建立

CREATE TABLE `fullpath` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `path` varchar(255) DEFAULT NULL COMMENT '全路徑',
  `catename` varchar(255) DEFAULT NULL COMMENT '分類名稱',
  `cateorder` int(11) DEFAULT NULL COMMENT '排序',
  `createtime` int(11) DEFAULT NULL COMMENT '建立時間',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
複製程式碼

2.為我們的資料表新增適當的測試資料

INSERT INTO `fullpath` VALUES (1,'','手機',0,0),(2,'1','功能手機',0,0),(3,'1.2','老人手機',0,0),(4,'1.2','兒童手機',0,0),(5,'1','智慧手機',0,0),(6,'1.5','IOS手機',0,0),(7,'1.5','WinPhoto手機',0,0),(8,'1.5','android手機',0,0),(9,'1.2.4','色盲手機',0,0),(10,'1.2.3','大字手機',0,0);
複製程式碼

案例:1

編寫獲通過全路徑方式取無限極分類列表的方法

程式設計思路:

1.獲取所有的分類資料,並按全路徑欄位排序

2.遍歷資料,根據全路徑的層級深度設定對應的級別層次

$full_tree=$this->get_full_tree();

    /**
     * 作者:逍遙俠
     * 建立時間:2018/10/29
     * @return mixed 返回資料
     */
    public function get_full_tree(){
        //獲取所有的分類資料,並通過full欄位排序
        $data=DB::table('fullpath')->select(DB::raw('id,catename,path,concat(path,\'.\',id) as full'))->orderBy('full','asc')->get();
        //遍歷所有資料
        foreach ($data as $k=>$v){
            //根據過濾後的全路徑欄位獲取對應的分類層級等級
         $data[$k]->level=count(explode('.',trim($v->full,'.')));
        }
        return $data;
    }
#注意由於我們資料表的欄位是沒有full這個欄位的,所以我們使用mysql裡的concat函式,利用對應的資料的path欄位與id欄位結合一個新的欄位。該sql的原生寫法為:
select id,path,catename,concat(path,'.',id) as full from `fullpath` order by full asc 

#執行結果
Collection {#616 ▼
  #items: array:10 [▼
    0 => {#605 ▼
      +"id": 1
      +"catename": "手機"
      +"path": ""
      +"full": ".1"
      +"level": 1
    }
    1 => {#606 ▼
      +"id": 2
      +"catename": "功能手機"
      +"path": "1"
      +"full": "1.2"
      +"level": 2
    }
    2 => {#607 ▼
      +"id": 3
      +"catename": "老人手機"
      +"path": "1.2"
      +"full": "1.2.3"
      +"level": 3
    }
    3 => {#608 ▼
      +"id": 10
      +"catename": "大字手機"
      +"path": "1.2.3"
      +"full": "1.2.3.10"
      +"level": 4
    }
    4 => {#609 ▼
      +"id": 4
      +"catename": "兒童手機"
      +"path": "1.2"
      +"full": "1.2.4"
      +"level": 3
    }
    5 => {#610 ▼
      +"id": 9
      +"catename": "色盲手機"
      +"path": "1.2.4"
      +"full": "1.2.4.9"
      +"level": 4
    }
    6 => {#611 ▼
      +"id": 5
      +"catename": "智慧手機"
      +"path": "1"
      +"full": "1.5"
      +"level": 2
    }
    7 => {#612 ▼
      +"id": 6
      +"catename": "IOS手機"
      +"path": "1.5"
      +"full": "1.5.6"
      +"level": 3
    }
    8 => {#613 ▼
      +"id": 7
      +"catename": "WinPhoto手機"
      +"path": "1.5"
      +"full": "1.5.7"
      +"level": 3
    }
    9 => {#614 ▼
      +"id": 8
      +"catename": "android手機"
      +"path": "1.5"
      +"full": "1.5.8"
      +"level": 3
    }
  ]
}複製程式碼

案例2:

編寫獲通過全路徑方式取麵包導航的方法

程式設計思路:

1.根據傳入的ID獲取對應ID

2.根據全路徑欄位,把字串分割為陣列

3.根據分割的陣列,利用wherein方法獲取包含的資料

$full_bread=$this->get_full_bread(10);

  /**
     * 作者:逍遙俠
     * 建立時間:2018/10/29
     * @param $id 傳入的對應ID
     * @return mixed 返回資料
     */
    //獲取全路徑麵包屑導航
    public function get_full_bread($id){
        //根據ID獲取全路徑的麵包屑導航
        $data=DB::table('fullpath')->select(DB::raw('id,catename,path,concat(path,\'.\',id) as full'))->orderBy('full','asc')->find($id);
        //分割對應的全路徑陣列
        $ids=explode('.',trim($data->full,'.'));
        //根據分割的ID陣列獲取對應的資料
        $bread=DB::table('fullpath')->wherein('id',$ids)->orderby('id','asc')->get();
        return $bread;
    }

#執行結果
Collection {#667 ▼
  #items: array:4 [▼
    0 => {#662 ▼
      +"id": 1
      +"path": ""
      +"catename": "手機"
      +"cateorder": 0
      +"createtime": 0
    }
    1 => {#663 ▼
      +"id": 2
      +"path": "1"
      +"catename": "功能手機"
      +"cateorder": 0
      +"createtime": 0
    }
    2 => {#664 ▼
      +"id": 3
      +"path": "1.2"
      +"catename": "老人手機"
      +"cateorder": 0
      +"createtime": 0
    }
    3 => {#665 ▼
      +"id": 10
      +"path": "1.2.3"
      +"catename": "大字手機"
      +"cateorder": 0
      +"createtime": 0
    }
  ]
}
複製程式碼

#到此本次基於不同方式的無限遞迴的常見寫法已經介紹完畢。由於小俠才疏學淺,如果各位有更好的方法,或者覺得程式碼有什麼不當的之處記得留意。我會盡快修改!


相關文章