tp5框架前台无限极导航菜单类实现方法分析


Posted in PHP onMarch 29, 2020

本文实例讲述了tp5框架前台无限极导航菜单类实现方法。分享给大家供大家参考,具体如下:

适用于 id name pid sort 类似结构的表结构

使用方法:(tp5)

1、将最下面的代码保存到“前台”控制器目录下(名为 FrontNav.php),比如(路径): application/index/controll(应用/模块/控制器)

2、在控制器中使用:(application/index/controll/index)(应用/模块/控制器/方法)

也可以放到基础类的初始化方法中,如:Base.php 的 _initialize() 方法(不用多解释,这个是 tp5 的初始化方法 貌似 init() 也行?可以自己试试)

使用:

1)、第一步:先实例化本类, 5 个参数。

参数说明:

  • param 1:必填 字符串类型 数据表名称(也是模型名称),不用其实字母大写也行。例如: category
  • param 2:选填 字符串类型 模型所在的路径(默认是:admin模块下的model目录)。如果你不叫 admin,那么书写格式如下:houtai/model
  • param 3:必填 字符串类型 父级栏目字段名称,例如:pid(parent id)
  • param 4:选填 数组类型 默认是按 id 正序排序的,如果有排序字段 sortField 的值为 字段名称 如 sort 或者 listorder 等…,sortOrder 的值为 asc(正序) 或 desc (倒序),建议按这个排序,要不然会显示有点乱,因为权重的关系需要手动排序显示的位置。
  • param 5:必填 二维数组 替换关键词,该参数的第一个数组为顶部导航所需要替换的关键词(必填),linkUrl(url 链接)是固定模式,必须这么写,它的值是:模块/控制器/方法,其他的键为要替换的关键词值为字段名称。第二个数组(选填)为二级菜单,第三个数组(选填)为N级菜单,此三个数组个数要对应 $this->createNavHtml() 方法中模版参数的个数,详见 createNavHtml() 方法解释。
$frontNav = new FrontNav('category', '', 'pid', array(
'sortField' => 'sort',
'sortOrder' => 'asc'
), array(
array(
'linkUrl' => 'index/artlist/index',
'catName' => 'name',
'catDesc' => 'desc'
),
array(
'linkUrl' => 'index/artlist/index',
'catName' => 'name',
'catDesc' => 'desc'
)
));

2)、第二步:生成 导航的 html 结构,4个参数

  1. param 1:选填 字符串类型 首页的 html 模版,例如 ‘<li><a class=”navi_home” href=”/”>首页</a></li>'
  2. param 2:必填 数组类型 顶部导航的 html 模版,注意下面实例的格式写法
  3. param 3:选填 数组类型 二级菜单的 html 模版,同上
  4. param 4:选填 数组类型 N级菜单的 html 模版,同上
$navHtml = $frontNav->createNavHtml('<li><a class="navi_home" href="/" rel="external nofollow" rel="external nofollow" >首页</a></li>', array(
'<ul id="jsddm" class="topNav">',
'<li><a href="linkUrl" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="catDesc">catName</a>',
'</li>',
'</ul>'
), array(
'<ul class="twoLevel">',
'<li><a href="linkUrl" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="catDesc">catName</a>',
'</li>',
'</ul>'
), '');

3)、第三步:向模版输出

$this->assign(array(
'navHtml' => $navHtml
));

4)、第四步:模版调用(多余??)

<div id="navi">
{$navHtml}
</div>

提示:

1、替换关键词参数个数与模版(除了首页外)参数个数一定要对应,打字解释的可能有点不明白,详细的对照 实例化 和 创键方法 的代码看几遍就明白了,实在不行可以看源程序,都有较详细的注释。

2、本类默认模型优先,如果没有模型就会查表返回数据库实例。

3、还有一点要注意就是你的替换关键词尽量要跟模版里的字符串不要重复,比如说,你的替换关键词叫 ‘id' => catename,而模版里 <li id=”xixixi”><a href=”###”>哎呀?</a></li>,要是这样就坏了…

求高手改成php原生的,可联系qq发给我吗?嘿嘿…

具体哪有不清楚的可以联系我QQ

效果图:(好像也支持无限极菜单)

<?php
  /**
   * Created by PhpStorm.
   * User: Chao Chao
   * Date: 2017/9/23
   * Time: 10:18
   * versions: 1.0.0
   * url: null
   * email: 2776332953@qq.com
   * phone: ***
   */
  namespace app\index\controller;
  use think\Db;    // 引用 Db (数据库链接) 类
  use think\Url;   // 引用 Url ( 创建 url) 类
  use think\Loader;  // 引用 Loader ( 加载 ) 类
  class FrontNav {
    // 数据库实例
    protected $db;
    // 无限极字段名称
    protected $pidName = '';
    // 排序设置
    protected $sort = array();
    // 一级导航html模版
    protected $levelOne = array();
    // 二级导航html模版
    protected $levelTwo = array();
    // n级导航html模版
    protected $levelN = array();
    // nav html
    protected $navHtml = '';
    // 替换关键词
    protected $replaceKeywords = array();
    /**
     * FrontNav constructor.  构造方法用于生成数据实例与配置参数
     * @param string $name 数据表名称或模型名称
     * @param string $modelPath 模型所在路径,默认为 admin/model (admin模块下的model目录)
     * @param string $pidName 无限极分类的字段(如:pid 或 parentid 等)
     * @param string $sort 要排序的字段名称
     * @param array $replaceKeywords 定义的替换关键词
     */
    public function __construct($name, $modelPath, $pidName, $sort, $replaceKeywords) {
      // $name 为必填参数
      if (empty($name) || !is_string($name)) {
        throw new \think\Exception('参数错误 $name(表名称或模型名称),实例化时该参数必须为字符串类型且不能为空!');
      }
      // 模型优先考虑 如果 模型类先存在 就返回 模型实例,否则返回 Db 类实例。
      // 防止大小写错误,先都转换成小写在将第一个字母大写 如:Category,因为 linux 区分大小写
      $fileName = ucwords(strtolower($name));
      // 一般栏目的模型都在后台,所以这里就写死了地址 '/admin/model/',也可以传参制定位置
      $modelPath = !empty($modelPath) ? strtolower($modelPath) : 'admin/model';
      if (class_exists('app\\' . str_replace('/', '\\', $modelPath) . '\\' . $fileName)) {
        $this->db = Loader::model($fileName, 'model', false, 'admin');
      } else {
        // 不确定在 linux 下数据库名称是否区分大小写,所以都转换成小写。
        $this->db = Db::name(strtolower($fileName));
      }
      // 无限极父类字段不能为空
      if (!empty($pidName)) {
        $this->pidName = $pidName;
      } else {
        throw new \think\Exception('参数错误 $pidName(父栏目id),实例化时字段名称不能为空!');
      }
      // 替换关键词
      if (empty($replaceKeywords) || !is_array($replaceKeywords)) {
        throw new \think\Exception('参数错误 $replaceKeywords(替换关键词),实例化时该参数必须是而为数组类型且不能为空!');;
      } else {
        $this->replaceKeywords = $replaceKeywords;
      }
      $this->sort = $sort;
    }
    /**
 * 控制器调用,生成导航菜单。顶层导航的样式( 参数2 $levelOneTemplate )为必填项,也就是说最基本的是一层导航,二级和多级是选填项( 参数3: $levelTwoTemplate 与 参数4 $levelNTemplate 非必填项 )
     * @param string $homePageHml 首页 标签的html样式,如: <li><a class="navi_home" href="/" rel="external nofollow" rel="external nofollow" >首页</a></li>
     * @param array $levelOneTemplate 必填 顶部导航的html样式,如: array(
     * '<ul id="jsddm" class="topNav">',  最外层 ul
     * '<li><a href="linkUrl" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="catDesc">catName</a>',  li标签
     * '</li>',  li 结束
     * '</ul>' ul 结束
     * )
     * @param array $levelTwoTemplate 选填 二级菜单的html样式,如: array(
     * '<ul class="twoLevel">',  二级菜单的 ul
     * '<li><a href="linkUrl" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="catDesc">catName</a>',  li标签
     * '</li>',li 结束
     * '</ul>'ul 结束
     * )
     * @param array $levelNTemplate 选填 多级菜单的html样式,如: array(
     * '<ul class="nLevel">',  N级菜单的 ul
     * '<li><a href="linkUrl" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" title="catDesc">catName</a>',  li标签
     * '</li>',li 结束
     * '</ul>'ul 结束
     * @return string
     */
    public function createNavHtml($homePageHml, $levelOneTemplate, $levelTwoTemplate, $levelNTemplate) {
      // 第一层导航不能为空且必须是数组
      if (empty($levelOneTemplate) || !is_array($levelOneTemplate)) {
        throw new \think\Exception('参数错误 $levelOneTemplate(一级导航模版),该参数必须是数组类型且不能为空!');
      }
      $this->levelOne = $levelOneTemplate;
      // 二级导航
      if (!empty($levelTwoTemplate) && !is_array($levelTwoTemplate)) {
        throw new \think\Exception('参数错误 $levelTwoTemplate(二级导航模版),该参数可以为空 \'\' 或 array(),否则必须是数组类型!');
      }
      $this->levelTwo = $levelTwoTemplate;
      // N级导航
      if (!empty($levelNTemplate) && !is_array($levelNTemplate)) {
        throw new \think\Exception('参数错误 $levelNTemplate(N级导航模版),该参数可以为空 \'\' 或 array(),否则必须是数组类型!');
      }
      $this->levelN = $levelNTemplate;
      $treeData = $this->getTreeData($this->getAllData(), 0);
      //print_r($treeData);
      $this->createHtml($treeData);
      return $this->levelOne[0] . (!empty($homePageHml) ? $homePageHml : '') . $this->navHtml .
          $this->levelOne[3] . "\n";
    }
    /**
     * 获取所有数据
     * @return array
     */
    private function getAllData() {
    if (empty($this->sort) || empty($this->sort['sortField']) || empty($this->sort['sortOrder'])) {
        return collection($this->db->where(1)
                      ->select())->toArray();
      } else {
        return collection($this->db->where(1)
                      ->order($this->sort['sortField'] . ' ' . $this->sort['sortOrder'])
                      ->select())->toArray();
      }
    }
    /**
     * 将所有数据攒成树状结构的数组
     * 增加 levels (层级) children (子数组)
     * @param $allData   传递过来的所有非树状结构的数组
     * @param $parentId   初始化时的父栏目id
     * @return array    树状结构的数组
     */
    private function getTreeData($allData, $parentId) {
      $tree = array();
      // 层级计数
      static $number = 1;
      foreach ($allData as $v) {
        if ($v[$this->pidName] == $parentId) {
          if ($v[$this->pidName] == 0) {
            $v['levels'] = 0;
          } else {
            $v['levels'] = $number;
            ++$number;
          }
          $v['children'] = $this->getTreeData($allData, $v['id']);
          $tree[] = $v;
        } else {
          $number = 1;
        }
      }
      return $tree;
    }
    /**
     * 递归生成树状结构的html
     * @param $allData array  由 createNavHtml() 方法传递过来的 树形结构 数据(数组)
     * @return     string 返回(最外层ul内部的html)树状结构的html
     */
    private function createHtml($allData) {
      foreach ($allData as $v) {
        // 顶部导航
        if ($v['levels'] == 0) {
          $tempStr0 = $this->levelOne[1];
          foreach ($this->replaceKeywords[0] as $k1 => $v1) {
            if ($k1 == 'linkUrl') {
              $tempStr0 = str_replace($k1, Url::build($v1, 'id=' . $v['id']), "\n" . $tempStr0);
            } else {
              $tempStr0 = str_replace($k1, $v[$v1], $tempStr0);
            }
          }
          $this->navHtml .= $tempStr0;
          if (empty($v['children'])) {
            $this->navHtml .= $this->levelOne[2] . "\n";
          } else if (!empty($v['children']) && !empty($this->levelTwo)) {
            $this->navHtml .= "\n" . $this->levelTwo[0] . "\n";
            $this->createHtml($v['children']);
            $this->navHtml .= $this->levelTwo[3] . $this->levelOne[2];
          }
        }
        // 二级菜单
        if ($v['levels'] == 1) {
          $tempStr2 = $this->levelTwo[1];
          foreach ($this->replaceKeywords[1] as $k1 => $v1) {
            if ($k1 == 'linkUrl') {
              $tempStr2 = str_replace($k1, Url::build($v1, 'id=' . $v['id']),       $tempStr2);
            } else {
              $tempStr2 = str_replace($k1, $v[$v1], $tempStr2);
            }
          }
          $this->navHtml .= $tempStr2;
          if (empty($v['children'])) {
            $this->navHtml .= $this->levelTwo[2] . "\n";
          } else if (!empty($v['children']) && !empty($this->levelN)) {
            // 是否多级导航,有 children ,还必须有3级 html 模版
            $this->navHtml .= "\n" . $this->levelN[0] . "\n";
            $this->createHtml($v['children']);
            $this->navHtml .= $this->levelN[3] . $this->levelTwo[2] . "\n";
          }
        }
        // 多级菜单
        if (!empty($this->levelN) && $v['levels'] > 1) {
          $tempStrN = $this->levelN[1];
          foreach ($this->replaceKeywords[2] as $k1 => $v1) {
            if ($k1 == 'linkUrl') {
              $tempStrN = str_replace($k1, Url::build($v1, 'id=' . $v['id']), $tempStrN);
            } else {
              $tempStrN = str_replace($k1, $v[$v1], $tempStrN);
            }
          }
          $this->navHtml .= $tempStrN;
          if (empty($v['children'])) {
            $this->navHtml .= $this->levelN[2] . "\n";
          } else {
            $this->navHtml .= $this->levelN[0];
            $this->createHtml($v['children']);
            $this->navHtml .= $this->levelN[3] . $this->levelN[2];
          }
        }
      }
      return $this->navHtml;
    }
  }

希望本文所述对大家基于ThinkPHP框架的PHP程序设计有所帮助。

PHP 相关文章推荐
提升PHP执行速度全攻略(上)
Oct 09 PHP
php 采集书并合成txt格式的实现代码
Mar 01 PHP
一些被忽视的PHP函数(简单整理)
Apr 30 PHP
php 数组动态添加实现代码(最土团购系统的价格排序)
Dec 30 PHP
php结合ajax实现赞、顶、踩功能实例
May 12 PHP
PHP字符串word末字符实现大小写互换的方法
Nov 10 PHP
php查看网页源代码的方法
Mar 13 PHP
分享自定义的几个PHP功能函数
Apr 15 PHP
CI框架简单邮件发送类实例
May 18 PHP
PHP常用排序算法实例小结【基本排序,冒泡排序,快速排序,插入排序】
Feb 07 PHP
Thinkphp5 自定义上传文件名的实现方法
Jul 23 PHP
php多进程中的阻塞与非阻塞操作实例分析
Mar 04 PHP
PHP中类与对象功能、用法实例解读
Mar 27 #PHP
php设计模式之职责链模式实例分析【星际争霸游戏案例】
Mar 27 #PHP
php设计模式之组合模式实例详解【星际争霸游戏案例】
Mar 27 #PHP
PhpStorm的使用教程(本地运行PHP+远程开发+快捷键)
Mar 26 #PHP
CentOS7系统搭建LAMP及更新PHP版本操作详解
Mar 26 #PHP
Centos7安装swoole扩展操作示例
Mar 26 #PHP
PHP开发api接口安全验证操作实例详解
Mar 26 #PHP
You might like
PHP中的cookie
2006/11/26 PHP
PHP date函数参数详解
2006/11/27 PHP
php命令行使用方法和命令行参数说明
2014/04/08 PHP
ThinkPHP使用心得分享-分页类Page的用法
2014/05/15 PHP
PHP实现批量修改文件后缀名的方法
2015/07/30 PHP
Laravel框架使用monolog_mysql实现将系统日志信息保存到mysql数据库的方法
2018/08/16 PHP
js中将HTMLCollection/NodeList/伪数组转换成数组的代码
2011/07/31 Javascript
通过上下左右键和回车键切换光标实现代码
2013/03/08 Javascript
JavaScript检测上传文件大小的方法
2015/07/22 Javascript
JavaScript利用HTML DOM进行文档操作的方法
2016/03/28 Javascript
Ext JS动态加载JavaScript创建窗体的方法
2016/06/23 Javascript
localStorage的黑科技-js和css缓存机制
2017/02/06 Javascript
js实现华丽的九九乘法表效果
2017/03/29 Javascript
新手快速入门JavaScript装饰者模式与AOP
2019/06/24 Javascript
js+springMVC 提交数组数据到后台的实例
2019/09/21 Javascript
小程序实现密码输入框
2020/11/16 Javascript
[01:58]DOTA2上海特级锦标赛现场采访:RTZ这个ID到底好不好
2016/03/25 DOTA
Python2实现的LED大数字显示效果示例
2017/09/04 Python
python实现俄罗斯方块游戏
2020/03/25 Python
Python数据分析matplotlib设置多个子图的间距方法
2018/08/03 Python
使用TensorFlow实现二分类的方法示例
2019/02/05 Python
Python实现字符串匹配的KMP算法
2019/04/04 Python
numpy库与pandas库axis=0,axis= 1轴的用法详解
2019/05/27 Python
python安装dlib库报错问题及解决方法
2020/03/16 Python
大数据分析用java还是Python
2020/07/06 Python
使用HTML5 Canvas绘制圆角矩形及相关的一些应用举例
2016/03/22 HTML / CSS
历史系自荐信范文
2013/12/24 职场文书
微观物理专业自荐信
2014/01/26 职场文书
陈欧的广告词
2014/03/18 职场文书
小学先进集体事迹材料
2014/05/31 职场文书
协商一致解除劳动合同协议书
2014/09/14 职场文书
单位实习介绍信
2015/05/05 职场文书
2015年统计员个人工作总结
2015/07/23 职场文书
Redis遍历所有key的两个命令(KEYS 和 SCAN)
2021/04/12 Redis
如何用Laravel包含你自己的帮助函数
2021/05/27 PHP
nginx内存池源码解析
2021/11/20 Servers