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 相关文章推荐
用PHPdig打造属于你自己的Google[图文教程]
Feb 14 PHP
织梦模板标记简介
Mar 11 PHP
基于PHP创建Cookie数组的详解
Jul 03 PHP
PHP 输出URL的快捷方式示例代码
Sep 22 PHP
php检测iis环境是否支持htaccess的方法
Feb 18 PHP
php实现的一段简单概率相关代码
May 30 PHP
php实现的XML操作(读取)封装类完整实例
Feb 23 PHP
用PHP做了一个领取优惠券活动的示例代码
Jul 05 PHP
Yii框架分页技术实例分析
Aug 30 PHP
PHP-FPM 设置多pool及配置文件重写操作示例
Oct 02 PHP
Laravel创建数据库表结构的例子
Oct 09 PHP
PHP+Redis事务解决高并发下商品超卖问题(推荐)
Aug 03 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查询域名状态whois的类
2006/11/25 PHP
PHP提取数据库内容中的图片地址并循环输出
2010/03/21 PHP
php 数组的指针操作实现代码
2011/02/08 PHP
PHP批量去除BOM头代码分享
2015/06/26 PHP
php微信公众平台交互与接口详解
2016/11/28 PHP
破除网页鼠标右键被禁用的绝招大全
2006/12/27 Javascript
Js中的onblur和onfocus事件应用介绍
2013/08/27 Javascript
浏览器图片选择预览、旋转、批量上传的JS代码实现
2013/12/04 Javascript
全面解析Bootstrap排版使用方法(标题)
2015/11/30 Javascript
浅析AngularJs HTTP响应拦截器
2015/12/28 Javascript
jQuery实现从身份证号中获取出生日期和性别的方法分析
2016/02/25 Javascript
Knockoutjs 学习系列(二)花式捆绑
2016/06/07 Javascript
jQuery轮播图效果精简版完整示例
2016/09/04 Javascript
Bootstrap基本布局实现方法详解
2016/11/25 Javascript
浅谈Vue父子组件和非父子组件传值问题
2017/08/22 Javascript
es6函数之rest参数用法实例分析
2020/04/18 Javascript
[04:10]DOTA2英雄梦之声_第11期_圣堂刺客
2014/06/21 DOTA
Python中的urllib模块使用详解
2015/07/07 Python
Python实现的递归神经网络简单示例
2017/08/11 Python
Python基础教程之异常详解
2019/01/10 Python
Python 判断图像是否读取成功的方法
2019/01/26 Python
使用Python正则表达式操作文本数据的方法
2019/05/14 Python
利用python开发app实战的方法
2019/07/09 Python
python的几种矩阵相乘的公式详解
2019/07/10 Python
Python用类实现扑克牌发牌的示例代码
2020/06/01 Python
python如何控制进程或者线程的个数
2020/10/16 Python
使用CSS3实现SVG路径描边动画效果入门教程
2019/10/21 HTML / CSS
ZINVO手表官网:男士和女士手表
2019/03/10 全球购物
介绍一下XMLHttpRequest对象的常用方法和属性
2013/05/24 面试题
2014年化妆品销售工作总结
2014/12/01 职场文书
幼儿园工作总结2015
2015/04/01 职场文书
办公室年度工作总结2015
2015/05/21 职场文书
交通处罚决定书
2015/06/24 职场文书
nginx 反向代理之 proxy_pass的实现
2021/03/31 Servers
解决mysql问题:由于找不到MSVCR120.dll,无法继续执行代码
2021/06/26 MySQL
python神经网络 tf.name_scope 和 tf.variable_scope 的区别
2022/05/04 Python