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
Ext.data.PagingMemoryProxy分页一次性读取数据的实现代码
Apr 07 PHP
PHP session有效期session.gc_maxlifetime
Apr 20 PHP
如何判断php数组的维度
Jun 10 PHP
PHP在网页中动态生成PDF文件详细教程
Jul 05 PHP
PHP中创建图像并绘制文字的例子
Nov 19 PHP
php程序员应具有的7种能力小结
Nov 27 PHP
PHP中strcmp()和strcasecmp()函数字符串比较用法分析
Jan 07 PHP
PHP获取访问页面HTTP状态码的实现代码
Nov 03 PHP
thinkPHP订单数字提醒功能的实现方法
Dec 01 PHP
老生常谈ThinkPHP中的行为扩展和插件(推荐)
May 05 PHP
php实现和c#一致的DES加密解密实例
Jul 24 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将整个网站生成HTML纯静态网页的方法总结
2012/02/05 PHP
PHP 利用AJAX获取网页并输出的实现代码(Zjmainstay)
2012/08/31 PHP
golang 调用 php7详解及实例
2017/01/04 PHP
php实现用户登陆简单实例
2017/04/04 PHP
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
2007/09/04 Javascript
jQuery 淡出一个图像到另一个图像的实现代码
2013/06/12 Javascript
jquery实现类似EasyUI的页面布局可改变左右的宽度
2020/09/12 Javascript
Javascript前端UI框架Kit使用指南之kitjs事件管理
2014/11/28 Javascript
javascript+HTML5自定义元素播放焦点图动画
2016/02/21 Javascript
基于JavaScript实现轮播图代码
2016/07/14 Javascript
JS实现兼容火狐及IE iframe onload属性的遮罩层隐藏及显示效果
2016/08/23 Javascript
简单实现JS计算器功能
2016/12/21 Javascript
利用js定义一个导航条菜单
2017/03/14 Javascript
js实现延迟加载的几种方法
2017/04/24 Javascript
解决linux下node.js全局模块找不到的问题
2018/05/15 Javascript
Python中类的初始化特殊方法
2017/12/01 Python
python实现微信自动回复功能
2018/04/11 Python
python 读取txt,json和hdf5文件的实例
2018/06/05 Python
Python设置在shell脚本中自动补全功能的方法
2018/06/25 Python
python爬虫之urllib3的使用示例
2018/07/09 Python
python在html中插入简单的代码并加上时间戳的方法
2018/10/16 Python
Python 私有化操作实例分析
2019/11/21 Python
Python命名空间及作用域原理实例解析
2020/08/12 Python
澳洲的服装老品牌:SABA
2018/02/06 全球购物
澳大利亚在线生活方式商店:Mytopia
2018/07/08 全球购物
Zooplus罗马尼亚:宠物食品和配件
2019/11/02 全球购物
Ibatis中如何提高SQL Map的性能
2013/05/11 面试题
程序运行正确, 但退出时却"core dump"了,怎么回事
2014/02/19 面试题
写一个在SQL Server创建表的SQL语句
2012/03/10 面试题
2014厂务公开实施方案
2014/02/17 职场文书
超市创业计划书
2014/09/15 职场文书
千手观音观后感
2015/06/03 职场文书
孔繁森观后感
2015/06/10 职场文书
中学教师教学工作总结
2015/08/13 职场文书
创业计划书之青年旅馆
2019/09/23 职场文书
Python OpenCV实现传统图片格式与base64转换
2021/06/13 Python