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生成文件
Jan 15 PHP
PHP异步调用socket实现代码
Jan 12 PHP
解析PHP跨站刷票的实现代码
Jun 18 PHP
Laravel模板引擎Blade中section的一些标签的区别介绍
Feb 10 PHP
PHP中预定义的6种接口介绍
May 12 PHP
PHP的关于变量和日期处理的一些面试题目整理
Aug 10 PHP
CI框架入门之MVC简单示例
Nov 21 PHP
基于win2003虚拟机中apache服务器的访问
Aug 01 PHP
PHP调用API接口实现天气查询功能的示例
Sep 21 PHP
Laravel 简单实现Ajax滚动加载示例
Oct 22 PHP
如何在Laravel5.8中正确地应用Repository设计模式
Nov 26 PHP
php多进程并发编程防止出现僵尸进程的方法分析
Feb 28 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逐行读取txt文件写入数组的方法
2015/07/02 PHP
php实现微信发红包
2015/12/05 PHP
php版微信支付api.mch.weixin.qq.com域名解析慢原因与解决方法
2016/10/12 PHP
PHP实现的XML操作类【XML Library】
2016/12/29 PHP
详解cookie验证的php应用的一种SSO解决办法
2017/10/20 PHP
jquery 最简单的属性菜单
2009/10/08 Javascript
比较新旧两个数组值得增加和删除的JS代码
2013/10/30 Javascript
jquery操作cookie插件分享
2014/01/14 Javascript
jquery mobile动态添加元素之后不能正确渲染解决方法说明
2014/03/05 Javascript
js判断当前浏览器类型,判断IE浏览器方法
2014/06/02 Javascript
JavaScript合并两个数组并去除重复项的方法
2015/06/13 Javascript
Java  Spring 事务回滚详解
2016/10/17 Javascript
vue按需引入element Transfer 穿梭框
2017/09/30 Javascript
Js代码中的span拼接问题解决
2019/11/22 Javascript
JS 5种遍历对象的方式
2020/06/16 Javascript
使用Python编写Linux系统守护进程实例
2015/02/03 Python
Python Django框架实现应用添加logging日志操作示例
2019/05/17 Python
Python 给定的经纬度标注在地图上的实现方法
2019/07/05 Python
Django处理Ajax发送的Get请求代码详解
2019/07/29 Python
python中的线程threading.Thread()使用详解
2019/12/17 Python
解决pycharm下pyuic工具使用的问题
2020/04/08 Python
Pandas替换及部分替换(replace)实现流程详解
2020/10/12 Python
HTML5制作3D爱心动画教程 献给女友浪漫的礼物
2014/11/05 HTML / CSS
html5中canvas图表实现柱状图的示例
2017/11/13 HTML / CSS
BIBLOO捷克:购买女装、男装、童装、鞋和配件
2017/01/27 全球购物
欧舒丹澳洲版:L’OCCITANE
2017/07/17 全球购物
美国医生配方营养补充剂供应商:Healthy Directions
2019/07/10 全球购物
意大利领先的奢侈品在线时装零售商:MCLABELS
2020/10/13 全球购物
如何将一个描述日期或日期/时间的字符串转换为一个Date对象
2015/10/13 面试题
关于毕业的广播稿
2014/01/10 职场文书
社区党务公开实施方案
2014/03/18 职场文书
房屋鉴定委托书范本
2014/09/23 职场文书
广告设计专业毕业生自我鉴定
2014/09/27 职场文书
超详细教你怎么升级Mysql的版本
2021/05/19 MySQL
解决pytorch 损失函数中输入输出不匹配的问题
2021/06/05 Python
使用JS前端技术实现静态图片局部流动效果
2022/08/05 Javascript