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 一元分词算法
Nov 30 PHP
php数据库密码的找回的步骤
Jan 12 PHP
关于session在PHP5的配置文件中的详细设置参数说明
Apr 20 PHP
探讨:web上存漏洞及原理分析、防范方法
Jun 29 PHP
Thinkphp实现MySQL读写分离操作示例
Jun 25 PHP
php设计模式之简单工厂模式详解
Sep 04 PHP
浅谈php正则表达式中的非贪婪模式匹配的使用
Nov 25 PHP
PHP动态输出JavaScript代码实例
Feb 12 PHP
利用PHP命令行模式采集股票趋势信息
Aug 09 PHP
CI框架常用函数封装实例
Nov 21 PHP
[原创]php实现 data url的图片生成与保存
Dec 04 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
Nov 26 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
require(),include(),require_once()和include_once()的异同
2007/01/02 PHP
php木马webshell扫描器代码
2012/01/25 PHP
PHP中shuffle数组值随便排序函数用法
2014/11/21 PHP
php判断str字符串是否是xml格式数据的方法示例
2017/07/26 PHP
关于Curl在Swoole协程中的解决方案详析
2019/09/12 PHP
解析JavaScript中的不可见数据类型
2013/12/02 Javascript
我的Node.js学习之路(二)NPM模块管理
2014/07/06 Javascript
javascript使用正则获取url上的某个参数
2014/09/04 Javascript
Node.js中的缓冲与流模块详细介绍
2015/02/11 Javascript
js实现点击切换TAB标签实例
2015/08/21 Javascript
深入理解jQuery之防止冒泡事件
2016/05/24 Javascript
Bootstrap前端开发案例一
2016/06/17 Javascript
老生常谈javascript的类型转换
2016/10/12 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
纯原生js实现table表格的增删
2017/01/05 Javascript
bootstrap table 数据表格行内修改的实现代码
2017/02/13 Javascript
JS设计模式之数据访问对象模式的实例讲解
2017/09/30 Javascript
js实现同一个页面,多个enter事件绑定的示例
2018/10/10 Javascript
vue实现在v-html的html字符串中绑定事件
2019/10/28 Javascript
详解Typescript 内置的模块导入兼容方式
2020/05/31 Javascript
antd 表格列宽自适应方法以及错误处理操作
2020/10/27 Javascript
node.js爬虫框架node-crawler初体验
2020/10/29 Javascript
[01:28:31]《加油DOTA》真人秀 第五期
2014/09/01 DOTA
[02:15]你好,这就是DOTA!
2015/08/05 DOTA
Python学习笔记之解析json的方法分析
2017/04/21 Python
python中字符串类型json操作的注意事项
2017/05/02 Python
Python视频爬虫实现下载头条视频功能示例
2018/05/07 Python
Django Celery异步任务队列的实现
2019/07/24 Python
Python函数式编程指南:对生成器全面讲解
2019/11/19 Python
python 初始化一个定长的数组实例
2019/12/02 Python
Kivari官网:在线购买波西米亚服装
2018/10/29 全球购物
匈牙利最大的健身制造商和销售商:inSPORTline
2018/10/30 全球购物
美国亚马逊旗下男装网站:East Dane(支持中文)
2019/09/25 全球购物
职业规划实施方案
2014/06/10 职场文书
收入证明怎么写
2015/06/12 职场文书
腾讯云服务器部署前后分离项目之前端部署
2022/06/28 Servers