1. 程式人生 > 程式設計 >tp5框架前臺無限極導航選單類實現方法分析

tp5框架前臺無限極導航選單類實現方法分析

本文例項講述了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','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">','');

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: [email protected]
   * 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 結束
     * '</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 結束
     * '</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,$tempStr2);
            } else {
              $tempStr2 = str_replace($k1,$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,$tempStrN);
            } else {
              $tempStrN = str_replace($k1,$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相關內容感興趣的讀者可檢視本站專題:《ThinkPHP入門教程》、《thinkPHP模板操作技巧總結》、《ThinkPHP常用方法總結》、《codeigniter入門教程》、《CI(CodeIgniter)框架進階教程》、《Zend FrameWork框架入門教程》及《PHP模板技術總結》。

希望本文所述對大家基於ThinkPHP框架的PHP程式設計有所幫助。