美文网首页
无限级分类的简单实现

无限级分类的简单实现

作者: 洗耳恭听_kai | 来源:发表于2018-08-24 17:10 被阅读660次

    引子

    作为菜鸟的我面试过程中总是会被虐的体无完肤,即使知道是怎么一回事,但由于没有彻底掌握住,还是在关键时刻无法及时运用。所以多总结应该是我现在时常要做的事。
    遇到的这个机试题就是关于无限级分类的知识。无限级分类在项目中运用是比较平常的,逻辑也不会太难理解:一个父级下面包含多个子级。
    题目是这样的:点击下拉框选择,输入名称,添加,到对应的层级中。然后还要可以删除。
    实现大概效果图如下:


    图1
    图2

    实现

    1、数据库

    数据库

    添加的逻辑:当某行数据的pid等于另一行数据中的id时,如id为54的广州市,其pid=53,即对应的是广东省,所以广州市是在广东省下面的。以此类推。

    删除的逻辑:删除某个父类,其下所有子类都需删除。

    2、代码

    为了效果稍微好点,采取了jq\ajax,并用了mvc框架。

    Controller:
        public function index()
        {
            $data = DB::name('user')->order('id asc')->select();
            //调用树
            $li = new PersonModel;
            $tree = $li->getTree($data);
            $html = $li->html($tree);
            $this->assign('tree',$tree);
            $this->assign('data',$data);
            $this->assign('html',$html);
            return $this->fetch();
        }
    
        public function add()
        {
            $data = $_POST;
            $pid = $_POST['pid'];
            if($data) {
                if($pid == 0) {
                    $result = DB::name('user')->insert(['name'=>$data['name'],'pid'=>0]);//根目录
                } else {
                    $insert = DB::name('user')->insert(['name'=>$data['name'],'pid'=>$pid]);//子目录
                }
                
                $status = 1;
                $message = '成功';
                return ['status' => $status, 'message' => $message];
            } else {
                $status = 0;
                $message = '失败';
                return ['status' => $status, 'message' => $message];
            }
        }
        public function del()
        {
            $data = $_POST;
            $id = $_POST['id'];
            //获取子集ID
            $getIds = new PersonModel;
            $son_ids = $getIds->sonIds($id);
            $id .= $son_ids; //将删除的父级加上
            $ids = explode(',', $id);
            if($ids) {
                foreach ($ids as $key => $value) {
                    DB::name('user')->where("id='$value'")->delete();
                }
                $status = 1;
                $message = '成功';
                return ['status'=> $status, 'message' => $message];
            } else {
                $status = 0;
                $message = '失败';
                return ['status'=> $status,'message'=>$message];
            }
        }
    

    Model:

    //无极限分类---引用传参
        public function li($array)
        {
            $items = array();
            foreach ($array as $key => $value) {
                $items[$value['id']] = $value;
            }
            $tree = array();
            foreach ($items as $key => $value) {
                if(isset($items[$value['pid']])) {
                    $items[$value['pid']]['son'][] = &$items[$key];
                } else {
                    $tree[] = &$items[$key];
                }
            }
            return $tree;
        }
    
    //无极限分类--递归
        public function getTree($array, $pid =0, $level = 0){
    
            //声明静态数组,避免递归调用时,多次声明导致数组覆盖
            static $list = [];
            foreach ($array as $key => $value){
                //第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点
                if ($value['pid'] == $pid){
                    //父节点为根节点的节点,级别为0,也就是第一级
                    $value['level'] = $level;
                    //把数组放到list中
                    $list[] = $value;
                    //把这个节点从数组中移除,减少后续递归消耗
                    unset($array[$key]);
                    //开始递归,查找父ID为该节点ID的节点,级别则为原级别+1
                    $this->getTree($array, $value['id'], $level+1);
    
                }
            }
            return $list;
        }
    //输出效果
        public function html($tree)
        {
            foreach ($tree as $key => $value) {
                echo str_repeat('|----', $value['level']), $value['name'].'<br />';
            }
        }
    
    //获取删除中的子id集
        public function sonIds($id)
        {
            $ids = '';
            $data = DB::name('user')->where("pid='$id'")->select();
            if($data) {
                    foreach ($data as $key => $value) {
                        $ids .= ','.$value['id'];
                        $ids .= $this->sonIds($value['id']);
                    }
            }
            return $ids;
        }
    

    其中有两种方法实现:递归和引用

    前端:

    <!DOCTYPE html>
    <html>
    <meta charset="utf-8">
    <head>
        <title>无限级分类</title>
    </head>
    <body>
    <div>
    {$html}
            <form action="" method="post" id="formadd">
                选择:
                <div>
                    <select name="selected" id="sel">
                        <option value="0">根</option>
                    {foreach $data as $val}
                        <option value="{$val['id']}">{$val['name']}</option>
                    {/foreach}
                    </select>
                
                添加分类:
                
                    <input type="text" name="add" id="content"><button id="add">添加</button>
                
                </div>
            </form>
        <div>
            选择:
            <select name="delselect" id="del">
            {foreach $data as $va}
                <option value="{$va['id']}">{$va['name']}</option>
            {/foreach}
            </select>
            <button id="delete">删除</button>
        </div>
    </div>
    </body>
    <script type="text/javascript" src="../../mvc/public/js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
    
    $("#add").on('click',function(){
        var select = $("#sel").val();
        var name = $("#content").val();
        console.log(select);
        $.ajax({
            type: 'post',
            async:false,
            url:"{:url('index/index/add')}",
            data:{name:name,pid:select},
            datatype:'json',
            success:function (data) {
                //console.log(data.status);
                if(data.status == 1){
                    //alert('成功');
                    widows.location.reload()
                } else {
                    alert('失败');
                }
            },
            error:function (data) {
                alert('直接失败');
            }
        })
    });
    $("#delete").on('click',function(){
        var select = $("#del").val();
        confirm('删除要谨慎,确认要删除吗?');
        console.log(select);
        $.ajax({
            type: 'post',
            async:false,
            url:"{:url('index/index/del')}",
            data:{id:select},
            datatype:'json',
            success:function (data) {
                console.log(data);
                if(data.status == 1){
                    //alert('成功');
                    location.reload()
                } else {
                    alert('失败');
                }
            },
            error:function (data) {
                //alert('直接失败');
                console.log(data);
            }
        })
    })
    </script>
    </html>
    

    3、代码分析

    添加功能:

    添加的两种方法:递归和引用,其原理都一样,建立一个空数组,然后就是父亲找儿子的过程,将对应的儿子放在父亲下面。再将其放入空数组中,形成树结构。添加的功能其实就是一个ajax的实现,主要是显示到html中的查询代码处理。逻辑顺序是:选择对应的父类,获取其id,name添加到数据库,model里的方法处理要显示出来的内容。最后返回给页面。

    & 引用,将指针指向原数据,后面再循环的时候添加改变数据则是在原数据上改变,所以,可改变原数组。

    .= 点等于的意思是拼接等号左右两边的值,如 a = 1,b = 2,则 a .= ','.b 为1,2

    删除功能

    通过点击选择父类id,查找出其下所有子id。方法就是通过上面说的点等于符号,在遍历中将其所有的id封装成一个字符串返回。再拼接上父级id,最后使用explode函数将字符串变成数组。

    总结

    php中无限级分类实现的常用两种方法——递归与引用。

    相关文章

      网友评论

          本文标题:无限级分类的简单实现

          本文链接:https://www.haomeiwen.com/subject/euxiiftx.html