讓你的thinkphp支援巢狀繼承模板
最近想把後臺重寫一下,不想再用iframe了,用整頁跳轉的,當然想到的就是把之前那些固定的選單做成一個模板,然後挖坑,內容頁就填充到坑裡
thinkphp裡面有模板繼承的功能 extend,可我發現它居然不支援巢狀繼承
比如我寫一個只加載bootstrap框架的basic頁basic.html(放在Common/View/Boot/basic.html)
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <!--<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />--> <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,minimum-scale =1,user-scalable=no" /> <link rel="stylesheet" href="{$Think.PLUGIN_PATH}bootstrap/css/bootstrap.min.css" /> <link rel="stylesheet" href="{$Think.CSS_PATH}lc.css" /> <block name="head"></block> </head> <body> <block name="body"></block> <script src="{$Think.PLUGIN_PATH}jquery/jquery-1.11.3.min.js"></script> <script src="{$Think.PLUGIN_PATH}bootstrap/js/bootstrap.min.js"></script> <block name="foot"></block> </body> </html>
然後我再寫一個我後臺的admin_basic.html,繼承剛才的basic頁(放在Admin/View/Public/admin_basic.html),然後寫導航、選單,然後再挖坑。
<extend name="[email protected]:basic" /> <block name="body"> <div id="warpper"> <nav>頂部的導航</nav> <!-- 這兒用tp的Widget擴充套件讀取選單 --> <div id="page_menu">{:W("Admin/getAction")}</div> <div id="page-warpper"> <block name="body">內容頁</block> </div> </div> </block> <block name="foot"> <block name="foot"></block> </block>
然後我就寫後臺管理系統的首頁 index.html
<extend name="Public:admin_basic" />
<block name="body">
這是我的後臺系統管理
</block>
<block name="foot">
<script type="text/javascript">
$(function(){
alert("hello,world");
});
</script>
</block>
tp它居然預設無法這樣實現,我覺得這個功能應該是非常重要的呀,沒辦法,它不實現,只能我來實現了。
當然首先就是百度了,非常幸運,讓我找到下面這個大溼的部落格
具體是找到Thinkphp/Libray/Think/Template.class.php檔案,在245行附近的parseExtend方法中 $content = $this->replaceBlock($content);這句後面增加 $content = $this->parseExtend($content); 讓tp遞迴解析extend,然後再到340行附近的replaceBlock方法中,將 $content = $content[3]; 索引改為0。
請看下在程式碼,註釋有[2develop]
protected function parseExtend($content) {
$begin = $this->config['taglib_begin'];
$end = $this->config['taglib_end'];
// 讀取模板中的繼承標籤
$find = preg_match('/'.$begin.'extend\s(.+?)\s*?\/'.$end.'/is',$content,$matches);
if($find) {
//替換extend標籤
$content = str_replace($matches[0],'',$content);
// 記錄頁面中的block標籤
preg_replace_callback('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/is', array($this, 'parseBlock'),$content);
// 讀取繼承模板
$array = $this->parseXmlAttrs($matches[1]);
$content = $this->parseTemplateName($array['name']);
$content = $this->parseInclude($content, false); //對繼承模板中的include進行分析
// 替換block標籤
$content = $this->replaceBlock($content);
// [2DEVELOP] 支援多層繼承
$content = $this->parseExtend($content);
}else{
$content = preg_replace_callback('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/is', function($match){return stripslashes($match[2]);}, $content);
}
return $content;
}
private function replaceBlock($content){
static $parse = 0;
$begin = $this->config['taglib_begin'];
$end = $this->config['taglib_end'];
$reg = '/('.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.')(.*?)'.$begin.'\/block'.$end.'/is';
if(is_string($content)){
do{
$content = preg_replace_callback($reg, array($this, 'replaceBlock'), $content);
} while ($parse && $parse--);
return $content;
} elseif(is_array($content)){
if(preg_match('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'/is', $content[3])){ //存在巢狀,進一步解析
$parse = 1;
$content[3] = preg_replace_callback($reg, array($this, 'replaceBlock'), "{$content[3]}{$begin}/block{$end}");
return $content[1] . $content[3];
} else {
$name = $content[2];
//[2DEVELOP] 支援多層繼承,將下面原來的索引值3改為0
$content = $content[0];
$content = isset($this->block[$name]) ? $this->block[$name] : $content;
return $content;
}
}
}
我用它上面寫的方法後,發現真的成功了,但是!可能我比較糾結,我發現了一個小問題。
我發現如果我basic裡面的block的name名為body的話,我在admin_basic裡如果也挖了一個坑name也為body的話,它就會覆蓋admin_basic裡我在body的block裡寫的內容了,要不就得避免block的name值一樣。
我比較龜毛,一般主體我一直喜歡用body,所以我不能妥協!
讓我研究了一上午,終於讓我解決了
到Thinkphp/Libray/Think/Template.class.php
將345附近的$reg = '/('.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.')(.*?)'.$begin.'\/block'.$end.'/is';
改成下面這個
$reg = '/('.$begin.'block\sname=[\'"]([^\'"]+?)[\'"]\s*?'.$end.')([^(?!'.$begin.'block)]*?)'.$begin.'\/block'.$end.'/is';
</pre><pre name="code" class="php"> private function replaceBlock($content){
static $parse = 0;
$begin = $this->config['taglib_begin'];
$end = $this->config['taglib_end'];
//$reg = '/('.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.')(.*?)'.$begin.'\/block'.$end.'/is';
// [2DEVELOP]支援多層繼承,上面是原來的正則
$reg = '/('.$begin.'block\sname=[\'"]([^\'"]+?)[\'"]\s*?'.$end.')([^(?!'.$begin.'block)]*?)'.$begin.'\/block'.$end.'/is';
if(is_string($content)){
do{
$content = preg_replace_callback($reg, array($this, 'replaceBlock'), $content);
} while ($parse && $parse--);
return $content;
} elseif(is_array($content)){
if(preg_match('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'/is', $content[3])){ //存在巢狀,進一步解析
$parse = 1;
$content[3] = preg_replace_callback($reg, array($this, 'replaceBlock'), "{$content[3]}{$begin}/block{$end}");
return $content[1] . $content[3];
} else {
$name = $content[2];
$content = $content[3];
$content = isset($this->block[$name]) ? $this->block[$name] : $content;
return $content;
}
}
}
我也不知這樣改會不會有什麼錯誤,不過我看了我其它頁面都還沒發現有錯誤的現象,僅供參考學習。
相關推薦
讓你的thinkphp支援巢狀繼承模板
最近想把後臺重寫一下,不想再用iframe了,用整頁跳轉的,當然想到的就是把之前那些固定的選單做成一個模板,然後挖坑,內容頁就填充到坑裡 thinkphp裡面有模板繼承的功能 extend,可我發現它居然不支援巢狀繼承 比如我寫一個只加載bootstrap框架的basi
讓Proxmox VE支援巢狀虛擬化
目前公司的測試環境使用Proxmox VE(PVE),PVE虛擬出來的主機CPU預設不支援vmx,即不支援巢狀虛擬化,在虛擬機器中使用egrep "vmx|svm" /proc/cpuinfo驗證,無輸出,那麼如何讓他支援呢?其實PVE的核心還是採用了KVM+Qemu的方式模擬,那麼參照如何讓KVM支援巢狀虛
使ESXI host支援巢狀虛擬化hyperv
1.物理機要確保開啟支援巢狀虛擬化 vi /etc/vmware/config libdir = "/usr/lib/vmware" authd.proxy.vim = "vmware-hostd:hostd-vmdb" authd.proxy.nfc = "vmware
C++ 的巢狀類模板的特化定義不允許寫在類定義的範圍內
最近在使用在使用模板特化寫一段程式時發現一個奇怪的問題,比如像如下程式碼: #include <iostream>using namespace std;class CMyClass{public: template <typename T> struct test {
一張圖讓你搞懂JavaScript的繼承與原型鏈
前面的話 javascript裡的關係又多又亂。作用域鏈是一種單向的鏈式關係,還算簡單清晰;this機制的呼叫關係,稍微有些複雜;而關於原型,則是prototype、proto和constructor的三角關係。本文先用一張圖開宗明義,然後詳細解釋原型的三
Fragment懶載入(支援巢狀) 友盟統計Fragment時長最佳實踐
前言 在專案中我們可能需要獲取Fragment可見或者不可見時的回撥。(回撥這個詞在這裡用的可能並不準確,這裡理解為當Fragment可見或者不可見時能夠觸發一些方法,下同)。 Fragmeng生命週期中有onResume,onPause,這兩個生命週期是跟
三目運算支援巢狀
上原始碼:case DCH_MS: /* millisecond */ len = from_char_parse_int_len(&out->ms, &s, 3, n);
織夢channelartlist讓巢狀標籤裡的channel也支援currentstyle高亮
巢狀標籤 <div class="nav"> <ul> {dede:channelartlist row=7 typeid=top currentstyle=current} <li class="{dede:field.currents
MongoDB學習筆記~大叔框架實體更新支援N層巢狀~遞迴遞迴我愛你!
回到目錄 遞迴遞迴我愛你!只要你想做,就一定能成功! 從一到二,從二到三,它是容易的,也是沒什麼可搞的,或者說,它是一種流水線的方式,而從三到十,從十到百,它註定要有一個質的突破,否則,它會把你累死,程式碼寫的讓你自己都覺得想吐!有時,我們是被逼出來的,對於一種功能的實現,我們有時需要有從三到十的態度中,
Thinkphp獲取單個列陣列並用foreach和eq巢狀
1.Thinkphp 獲取單個列的陣列 $coins = M('coin')->getField('name_en',true); 2. foreach巢狀eq <foreach name="coins" item="vo"> &l
Python中函式巢狀以及函式巢狀的繼承
# a = 10 # b = 0 # c = 5 # try: # print("a的值是:%d,b的值是:%d"%(a,b)) # # f = c.open("a.txt") # print(f) # d = a / b # print("%d除以%d的值為
程式碼講解:面向物件下——程式碼塊、內部類、繼承(保證讓你全部都會噢)
//一、程式碼塊(筆試、面試常考知識點) //1.普通程式碼塊:普通程式碼塊就是定義在方法中的程式碼塊 // public class Lesson6{ // public static void main(String[] args){ // {//定義在main方法中的程式碼塊——
C++巢狀抽象類的繼承方式
今天在工作中遇到了一個問題,需要繼承一個巢狀的抽象類,廢了很大的功夫才成功建立了物件 抽象巢狀類如下: class A { class B { public: B* GetInstance() = 0; } }; 繼承類如下:
不同程式語言在發生stackoverflow之前支援的呼叫棧最大巢狀層數
今天我的一位同事在微信群裡發了一張圖片,勾起了我的好奇心:不同程式語言支援的函式遞迴呼叫的最大巢狀層數是? Java 1.8 private static void recur(int i){ System.out.println("Stack level: " +
模板巢狀類別名作為函式返回型別,可能會提示的編譯錯誤
模板巢狀類別名作為函式返回型別,可能會提示的編譯錯誤 1 #include <iostream> 2 using namespace std; 3 4 template<typename ElementType> 5 class B 6 { 7
讓你的ubuntu系統支援CPU動態調頻
首先,你得確保你的電腦是支援並且打開了CPU動態調頻功能的,方法如下: (我用的是的DELL機) (1)開機後進入BIOS,找到performance選項,在speedset子選項中你會看到你的CPU動態調頻是否開啟了,如果未開啟,要開啟。 (2)檢視你的核心是否安裝了
配置tomcat讓shtml巢狀檔案顯示
之前,我知道tomcat可以直接解析shtml檔案,在瀏覽器中顯示效果來,後來由於需求發生改變,比如說 在做靜態化生成的時候一個網站的頭部和底部都是一樣的,如果每個頁面都生成一次,顯然很浪費時間,所有我們可以把 這個共同的頭部 和底部挖出來單獨生成,然後通過sh
所見即所得,使用Java將HTML解析為Excel,支援多級表頭巢狀、單元格合併
最近專案需要實現如題“所見即所得”的功能,之前每次生成Excel都需要重新從資料庫查詢一遍,降低效率不說,那些巢狀的表頭實在是很難用Sql巢狀拼接實現。而且這樣做還沒有通用性,不同的表格需要寫不同的Sql實現,非常繁瑣。 在網上找了很
RecyclerView讓列表巢狀如此簡單
平常開發時,相信像這樣的頁面,大家一定是遇到過的。這裡比較坑爹的地方在於呢:列表巢狀。訂單列表中的每一項,都包含一個商品列表。像這種需求,大家會如何實現呢? 這裡呢,說一下我自己的思路,我沒有使用列表巢狀,而是,將原有的Order拆分成了三個佈局型別:Head、Body
手把手教你怎麼解析多層巢狀的JSON資料(使用JSONModel)
使用API API介紹 參考的JSON資料(可能與你看到的不同) { "date": "20181020", "stories": [ { "title": "每週一吸 · 狸花貓",