关于无限极分类,通过父ID或全路径的不同写法与简单分析说明

1,814 阅读6分钟

#在日常的项目中,我们常常会接触到无限极分类。一般情况下无限极分类有两种实现的方式。第一种方式是通过数据表中的父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
    }
  ]
}

#到此本次基于不同方式的无限递归的常见写法已经介绍完毕。由于小侠才疏学浅,如果各位有更好的方法,或者觉得代码有什么不当的之处记得留意。我会尽快修改!