Discuz!NT 模板机制分析(转)
雨雨也成了那時不少人關注的話題。而今天本人將結合在產品組中的開發經歷,介紹一下模板機制在設計
使用時的一些體會心得。希望借此陋文,使模板機制揭開“神秘”面紗,為大家在實際設計中提供一些有
價值的參考和建議。
??? 好了,開始今天的話題:)
??? 首先闡述一下模板設計的目標,因為這對于它最終要實現的功能非常重要??紤]到國內大部分站長基
本上都不具備.net開發背景,而我們的模板就是要降低這個門檻,便于站長進行設計訂制以及修改等。而
另一個目的就是要提升aspx頁面的訪問速度,所以我們并未在模板設計時引入(web)控件機制,因為如果
使用.net控件,在windows的臨時目錄中會進行控件的訂制生成(按用戶設置的屬性)。雖然在.net2.0
使用了fastobjectfactory的機制來提升頁面生成的效率,比如使用batch批量編譯選項 (web.config
文件中配置)生成的DLL(這里的DLL也是在臨時目錄下生成的隨機命名的DLL文件,且重復編譯的情況在所
難免)。但最終還是無法改變要生成服務器端控件的過程。
??
??? 我們在設計模板本身所提供的語法時,盡可能逼近HTML的書寫習慣,這樣只要有HTML編寫網頁經驗的
人就會很容易適應這種書寫方式。當然有 asp開發經驗的站長也能很快上手,因為模板的語法非常類似于
asp, 比如有<%if ...%>,<%else%>這樣的寫法等等。另外我們的模板語法也力求簡練精悍,只需很少的
語法規則就直接支持生成內容豐富且形式多樣的頁面。說了這些,相信大家已經有興趣來一看究竟了。不忙,
這里先要介紹一下如何使用模板機制來生成aspx頁面。因為我有一位從事.net開發多年的朋友,在一次聊
天時他說,修改我們的前臺頁面時要手工修改"aspx/.../"下的相應的aspx文件,而當他看到 aspx文件中
的內容時大吃一驚,舉個例子如下(aspx/1/logout.aspx):
.....命名空間和類的引用
?
?1<script?runat="server">?2override?protected?void?OnInit(EventArgs?e)
?3{
?4
?5?base.OnInit(e);
?6
?7?templateBuilder.Append("<!DOCTYPE?html?PUBLIC?\"-//W3C//DTD?XHTML?1.0?Transitional//EN
?8???\"?\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n");
?9?templateBuilder.Append("<html?xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
10?templateBuilder.Append("<head>\r\n");
11?templateBuilder.Append("<meta?http-equiv=\"Content-Type\"?content=\"text/html;?
12???charset=utf-8\"?/>\r\n");
13?templateBuilder.Append(""?+?meta.ToString()?+?"\r\n");
14?templateBuilder.Append("<title>"?+?pagetitle.ToString()?+?"?"?+?
15???config.Seotitle.ToString().Trim()?+?"?-?"?+?
16???config.Forumtitle.ToString().Trim()?+?"?-?Powered?by?Discuz!NT
17???</title>\r\n");
18?templateBuilder.Append("<link?rel=\"icon\"?href=\"favicon.ico\"?
19???type=\"image/x-icon\"?/>\r\n");
20?templateBuilder.Append("<link?rel=\"shortcut?icon\"?href=\"favicon.ico\"?
21???type=\"image/x-icon\"?/>\r\n");
22?templateBuilder.Append("<!--?調用樣式表?-->\r\n");
23?templateBuilder.Append("<link?rel=\"stylesheet\"?href=\"templates/"?+?
24???templatepath.ToString()?+?"/dnt.css\"?
25???type=\"text/css\"?media=\"all\"??/>\r\n");
26?templateBuilder.Append(""?+?link.ToString()?+?"\r\n");
27?templateBuilder.Append("<script?type=\"text/javascript\"?src=\"templates/"?+?
28???templatepath.ToString()?+?"/report.js\"></"?+?"script>\r\n");
29?templateBuilder.Append("<script?type=\"text/javascript\"?src=\"templates/"?+?
30???templatepath.ToString()?+?"/common.js\"></"?+?"script>\r\n");
31?templateBuilder.Append("<script?type=\"text/javascript\"?src=\"editor/common.js\">
32???</"?+?"script>\r\n");
33?templateBuilder.Append("<script?type=\"text/javascript\"?src=\"editor/menu.js\">
34???</"?+?"script>\r\n");
35?templateBuilder.Append(""?+?script.ToString()?+?"\r\n");
36?templateBuilder.Append("</head>\r\n");
37
38
39
??? 相信大家看到這樣的aspx頁面都會暈上一陣子,直接修改的想法已變得非常不現實了,簡直是“不
可能完成的任務”。而實際上,我們并不希望大家或站長來完成這項工作。因為這是系統自動生成的。
而生成的前提就是在template/下的模板“目錄”中的HTM文件。還是借用上面的logout,只是這里要看
的是模板目錄下同名的logout.htm模板文件。它的內容如下:
?
?1<%template?_header%>?2<div?id="foruminfo">
?3<div?class="userinfo">
?4???<h2><a?href="{config.forumurl}">{config.forumtitle}</a>?<strong>用戶退出</strong></h2>
?5</div>
?6</div>
?7<!--TheCurrent?end-->
?8<%template?_msgbox%>
?9</div>
10<%template?_footer%>
11
?
??? 大家可能會說,難道就是這幾行就實現了上面aspx頁面的內容嗎?當然不是了,請大家注意:
?????
1<%template?_header%>2
??? 這一行,其實就是告訴模板頁面生成器: 這是一個子模板。
??? 因為我們在開始設計模板機制時就想到要簡化模板代碼并提升可重用性,因此要支持子模板機制。
這就類似于設計網頁時的頁首和頁尾,我們在網頁引用時,只需要include進來即可,而當修改頁首和
頁尾時,只須變動相應文件即可。
??? 這里不妨再打開_header.htm(注意子模板名稱要用下劃線開頭),發現內容如下:
?
1<%template?_pageheader%>2<body>
3<div?id="append_parent"></div>
4<div?id="container">
5<!--header?start-->
6<div?id="header">
7?????.
8
9
??? 有意思,又是一個“子模板”出現在了第一行。不錯,我們的機制允許模板被嵌套使用,這樣會
使頁面的“組裝”更加靈活多樣。
??? 即然都走到這一步,不妨再打開_pageheader子模板,正所謂“不撞南墻不回頭”嘛:)
?
?1<!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Transitional//EN"?"http://www.w3.org/TR?2/xhtml1/DTD/xhtml1-transitional.dtd">
?3<html?xmlns="http://www.w3.org/1999/xhtml">
?4<head>
?5<meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>
?6{meta}
?7<title>{pagetitle}?{config.seotitle}?-?{config.forumtitle}?-?Powered?by?Discuz!NT</title>
?8<link?rel="icon"?href="favicon.ico"?type="image/x-icon"?/>
?9<link?rel="shortcut?icon"?href="favicon.ico"?type="image/x-icon"?/>
10<!--?調用樣式表?-->
11<link?rel="stylesheet"?href="templates/{templatepath}/dnt.css"?type="text/css"?media="all"/>
12{link}
13<script?type="text/javascript"?src="templates/{templatepath}/report.js"></script>
14<script?type="text/javascript"?src="templates/{templatepath}/common.js"></script>
15<script?type="text/javascript"?src="editor/common.js"></script>
16<script?type="text/javascript"?src="editor/menu.js"></script>
17{script}
18</head>
19
20
??? 折騰了一圈,到這里出現了上面aspx頁中的對應內容,有意思吧,不過里面的{pagetitle}和{
config.seotitle}以及{config.forumtitle}這樣的東東又是什么呢? 其實非常簡單,這就是按照模
板語法格式所書寫的代碼,因為這兩處在模板生成之后會變成
???
1?????templateBuilder.Append("<title>"?+?pagetitle.ToString()?+?"?"?+?2???config.Seotitle.ToString().Trim()?+?"?-?"?+?
3???config.Forumtitle.ToString().Trim()?+?"?-?Powered?by?Discuz!NT
4???</title>\r\n");
?
??? 好了,到了這里我們應該清楚了,以后要修改前臺頁面的一個標準流程:
??? 1.按模板語法修改相應的模板文件夾下的模板文件;
??? 2.在后臺生成或使用官方的模板生成器生成相應aspx頁面即可;
???
??? 其實流程非常簡單,相信即使不懂aspx開發的朋友也會很快適應并上手。前提就是要了解模板語
法,除了上面所說的以外,還有一些常用的語法如下圖:
???????
??? 這里不妨引用官方文檔中的鏈接,里面的說明會更清楚:)
??? 相關鏈接如下:http://nt.discuz.net/download/doc/dnt_2_skindoc.zip
?
??? 好了,目前我們只是知道了如使使用和修改它,但所謂的“模板生成”機制又是個什么樣子呢!
必定到這里我們只走完了一半旅途,下面將會介紹模板的生成機制。
??? 首先要看一下后臺的模板(列表)管理界面,如下圖:
?
??? 從上圖可知道,模板是按名稱(目錄)來進行管理的,而每個模板都有名稱,存放路徑,版權,
作者等相關信息。而這此信息都是來自于每個模板(目錄)下的about.xml文件,這里將它的內容貼
出來:
?
?1<?xml?version="1.0"?encoding="utf-8"??>??2<about>
?3?????<template?name="basic"
?4??????????author="Discuz!NT"
?5??????????createdate?=?"2007-11-12"
?6??????????ver="1.1112"
?7??????????fordntver="2.0"
?8??????????copyright="Copyright?2007?Comsenz?Inc."?/>
?9</about>
10
11
??? 注: 上圖中的那個“樂隊演出”圖片其實是模板目錄下的about.png文件,它相當于一張預覽圖。
??? 需要說明的是上圖中不是所有模板都能在前臺使用,而是當被標記為“已入庫”才可在前臺使用,
而入庫即數據庫,下面就是數據庫中的截圖:
?????
????
??? 而接下來要說的,就是模板列表中每個模板后面的“生成”鏈接所要干的活了。
??? 如果大家手頭上有reflector的話,請使用這個工具加載我們官方提供的產品目錄下的bin文件夾
中的discuz.common.dll文件,找到 PageTemplate這個類。這里為了便于說明,將反射所得到的代碼
加上注釋貼出來:
?
Code??1public?abstract?class?PageTemplate
??2?{
??3??public?static?Regex[]?r?=?new?Regex[21];
??4
??5??static?PageTemplate()
??6??{
??7
??8????????????????????????RegexOptions?options?=?Utils.GetRegexCompiledOptions();
??9
?10???r[0]?=?new?Regex(@"<%template?([^\[\]\{\}\s]+)%>",?options);
?11
?12???r[1]?=?new?Regex(@"<%loop?((\(([a-zA-Z]+)\)?)?)([^\[\]\{\}\s]+)?([^\[\]\{\}\s]+)%>",?options);
?13
?14???r[2]?=?new?Regex(@"<%\/loop%>",?options);
?15
?16???r[3]?=?new?Regex(@"<%while?([^\[\]\{\}\s]+)%>",?options);
?17
?18???r[4]?=?new?Regex(@"<%\/while?([^\[\]\{\}\s]+)%>",?options);
?19
?20???r[5]?=?new?Regex(@"<%if?(?:\s*)(([^\s]+)((?:\s*)(\|\||\&\&)(?:\s*)([^\s]+))?)(?:\s*)%>",?options);
?21
?22???r[6]?=?new?Regex(@"<%else((?(?:\s*)if?(?:\s*)(([^\s]+)((?:\s*)(\|\||\&\&)(?:\s*)([^\s]+))?))?)(?:\s*)%>",?options);
?23
?24???r[7]?=?new?Regex(@"<%\/if%>",?options);
?25
?26???//解析{var.a}
?27???r[8]?=?new?Regex(@"(\{strtoint\(([^\s]+?)\)\})",?options);
?28
?29???//解析{request[a]}
?30???r[9]?=?new?Regex(@"(<%urlencode\(([^\s]+?)\)%>)",?options);
?31
?32???//解析{var[a]}
?33???r[10]?=?new?Regex(@"(<%datetostr\(([^\s]+?),(.*?)\)%>)",?options);
?34???r[11]?=?new?Regex(@"(\{([^\.\[\]\{\}\s]+)\.([^\[\]\{\}\s]+)\})",?options);
?35
?36???//解析普通變量{}
?37???r[12]?=?new?Regex(@"(\{request\[([^\[\]\{\}\s]+)\]\})",?options);
?38
?39???//解析==表達式
?40???r[13]?=?new?Regex(@"(\{([^\[\]\{\}\s]+)\[([^\[\]\{\}\s]+)\]\})",?options);
?41
?42???//解析==表達式
?43???r[14]?=?new?Regex(@"({([^\[\]/\{\}='\s]+)})",?options);
?44
?45???//解析普通變量{}
?46???r[15]?=?new?Regex(@"({([^\[\]/\{\}='\s]+)})",?options);
?47
?48???//解析==表達式
?49???r[16]?=?new?Regex(@"(([=|>|<|!]=)\\"?+?"\""?+?@"([^\s]*)\\"?+?"\")",?options);
?50???
?51???//命名空間
?52???r[17]?=?new?Regex(@"<%namespace?([^\[\]\{\}\s]+)%>",?options);
?53???
?54???//C#代碼
?55???r[18]?=?new?Regex(@"<%csharp%>([\s\S]+?)<%/csharp%>",?options);
?56
?57???//set標簽
?58???r[19]?=?new?Regex(@"<%set?((\(([a-zA-Z]+)\))?)(?:\s*)\{([^\s]+)\}(?:\s*)=(?:\s*)(.*?)(?:\s*)%>",?options);
?59
?60????????????????????????r[20]?=?new?Regex(@"(<%getsubstring\(([^\s]+?),(.\d*?),(.\d*?),([^\s]+?)\)%>)",?options);
?61??}
?62
?63
?64??/**////?<summary>
?65??///?獲得模板字符串.?首先查找緩存.?如果不在緩存中則從設置中的模板路徑來讀取模板文件.
?66??///?模板文件的路徑在Web.config文件中設置.
?67??///?如果讀取文件成功則會將內容放于緩存中.
?68??///?</summary>
?69??///?<param?name="skinName">模板名</param>
?70??///?<param?name="templateName">模板文件的文件名稱,?也是緩存中的模板名稱.</param>
?71??///?<param?name="nest">嵌套次數</param>
?72??///?<param?name="templateid">模板id</param>
?73??///?<returns>string值,如果失敗則為"",成功則為模板內容的string</returns>
?74??public?virtual?string?GetTemplate(string?forumpath,string?skinName,?string?templateName,?int?nest,int?templateid)
?75??{
?76???StringBuilder?strReturn?=?new?StringBuilder();
?77???if?(nest?<?1)
?78???{
?79????nest?=?1;
?80???}
?81???else?if?(nest?>?5)
?82???{
?83????return?"";
?84???}
?85
?86
?87???string?extNamespace?=?"";
?88???string?pathFormatStr?=?"{0}{1}{2}{3}{4}.htm";
?89????????????????????????string?filePath?=?string.Format(pathFormatStr,?Utils.GetMapPath(forumpath?+?"templates"),?System.IO.Path.DirectorySeparatorChar,?skinName,?System.IO.Path.DirectorySeparatorChar,?templateName);
?90???
?91???//如果指定風格的模板文件不存在
?92???if?(!System.IO.File.Exists(filePath))
?93???{
?94????//默認風格的模板是否存在
?95????????????????????????????????filePath?=?string.Format(pathFormatStr,?Utils.GetMapPath(forumpath?+?"templates"),?System.IO.Path.DirectorySeparatorChar,?"default",?System.IO.Path.DirectorySeparatorChar,?templateName);
?96????if?(!System.IO.File.Exists(filePath))
?97????{
?98?????return?"";
?99????}
100???}
101???using(System.IO.StreamReader?objReader?=?new?System.IO.StreamReader(filePath,?Encoding.UTF8))
102???{
103????System.Text.StringBuilder?textOutput?=?new?System.Text.StringBuilder();
104????
105????textOutput.Append(objReader.ReadToEnd());
106????objReader.Close();
107
108????//處理命名空間
109????if?(nest?==?1)
110????{
111?????//命名空間
112?????foreach?(Match?m?in?r[17].Matches(textOutput.ToString()))
113?????{
114??????extNamespace?+=?"\r\n<%@?Import?namespace=\""?+?m.Groups[1].ToString()?+?"\"?%>";
115??????textOutput.Replace(m.Groups[0].ToString(),?string.Empty);
116?????}
117
118????}
119????//處理Csharp語句
120????foreach?(Match?m?in?r[18].Matches(textOutput.ToString()))
121????{
122?????//csharpCode?+=?"\r\n"?+?m.Groups[1].ToString()?+?"\r\n";
123?????textOutput.Replace(m.Groups[0].ToString(),?m.Groups[0].ToString().Replace("\r\n",?"\r\t\r"));
124????}
125
126????textOutput.Replace("\r\n",?"\r\r\r");
127????textOutput.Replace("<%",?"\r\r\n<%");
128????textOutput.Replace("%>",?"%>\r\r\n");
129
130????textOutput.Replace("<%csharp%>\r\r\n",?"<%csharp%>").Replace("\r\r\n<%/csharp%>",?"<%/csharp%>");
131????
132
133????string[]?strlist?=?Utils.SplitString(textOutput.ToString(),?"\r\r\n");
134????int?count?=?strlist.GetUpperBound(0);
135??
136????for?(int?i?=?0;?i?<=?count;?i++)
137????{
138?????strReturn.Append(ConvertTags(nest,forumpath,?skinName,?strlist[i],?templateid));
139????}
140???}
141???if?(nest?==?1)
142???{
143????????????????????????????????string?template?=?string.Format("<%@?Page?language=\"c#\"?Codebehind=\"{0}.aspx.cs\"?AutoEventWireup=\"false\"?EnableViewState=\"false\"?Inherits=\"Discuz.ForumPage.{0}\"?%>\r\n<%@?Import?namespace=\"System.Data\"?%>\r\n<%@?Import?namespace=\"Discuz.Common\"?%>\r\n<%@?Import?namespace=\"Discuz.Forum\"?%>\r\n<%@?Import?namespace=\"Discuz.Entity\"?%>\r\n{1}\r\n<script?runat=\"server\">\r\noverride?protected?void?OnInit(EventArgs?e)\r\n{{\r\n\r\n\t/*?\r\n\t\tThis?page?was?created?by?Discuz!NT?Template?Engine?at?{2}.\r\n\t\t本頁面代碼由Discuz!NT模板引擎生成于?{2}.?\r\n\t*/\r\n\r\n\tbase.OnInit(e);\r\n{3}\r\n\tResponse.Write(templateBuilder.ToString());\r\n}}\r\n</script>\r\n",?templateName,?extNamespace,?DateTime.Now.ToString(),?strReturn.ToString());
144
145????string?pageDir?=?Utils.GetMapPath(forumpath?+?"aspx\\"?+?templateid.ToString()?+?"\\");
146????if?(!Directory.Exists(pageDir))
147????{
148?????Utils.CreateDir(pageDir);
149????}
150
151????string?outputPath?=?pageDir??+?templateName?+?".aspx";
152????
153?????
154????
155????using?(FileStream?fs?=?new?FileStream(outputPath,?FileMode.Create,FileAccess.ReadWrite,?FileShare.ReadWrite))
156????{
157?????Byte[]?info?=?System.Text.Encoding.UTF8.GetBytes(template);
158?????fs.Write(info,?0,?info.Length);
159?????fs.Close();
160????}
161????
162???}
163???return?strReturn.ToString();
164??}
165??
166??/**////?<summary>
167??///?轉換標簽
168??///?</summary>
169??///?<param?name="nest">深度</param>
170??///?<param?name="skinName">模板名稱</param>
171??///?<param?name="inputStr">模板內容</param>
172??///?<param?name="templateid">模板id</param>
173??///?<returns></returns>
174??private?string?ConvertTags(int?nest,string?forumpath,?string?skinName,?string?inputStr,?int?templateid)
175??{
176???string?strReturn?=?"";
177???bool?IsCodeLine;
178???string?strTemplate;
179???strTemplate?=?inputStr.Replace("\\",?"\\\\");
180???strTemplate?=?strTemplate.Replace("\"",?"\\\"");
181???strTemplate?=?strTemplate.Replace("</script>",?"</\"?+?\"script>");
182???IsCodeLine?=?false;
183??
184
185???foreach?(Match?m?in?r[0].Matches(strTemplate))
186???{
187????IsCodeLine?=?true;
188????????????????????????????????strTemplate?=?strTemplate.Replace(m.Groups[0].ToString(),?"\r\n"?+?GetTemplate(forumpath,skinName,?m.Groups[1].ToString(),?nest?+?1,?templateid)?+?"\r\n");
189???}
190
191???foreach?(Match?m?in?r[1].Matches(strTemplate))
192???{
193????IsCodeLine?=?true;
194????if?(m.Groups[3].ToString()?==?"")
195????{
196?????strTemplate?=?strTemplate.Replace(m.Groups[0].ToString(),
197??????string.Format("\r\n\tint?{0}__loop__id=0;\r\n\tforeach(DataRow?{0}?in?{1}.Rows)\r\n\t{{\r\n\t\t{0}__loop__id++;\r\n",?m.Groups[4].ToString(),?m.Groups[5].ToString()));
198????}
199????else
200????{
201?????strTemplate?=?strTemplate.Replace(m.Groups[0].ToString(),
202??????string.Format("\r\n\tint?{1}__loop__id=0;\r\n\tforeach({0}?{1}?in?{2})\r\n\t{{\r\n\t\t{1}__loop__id++;\r\n",?m.Groups[3].ToString(),?m.Groups[4].ToString(),?m.Groups[5].ToString()));
203????}
204???}
205
206???
207
208???
209
210????
211???if?(IsCodeLine)
212???{
213????strReturn?=?strTemplate?+?"\r\n";
214???}
215???else
216???{
217????if?(strTemplate.Trim()?!=?"")
218????{
219?????StringBuilder?sb?=?new?StringBuilder();
220?????foreach?(string?temp?in?Utils.SplitString(strTemplate,"\r\r\r"))
221?????{
222??????if?(temp.Trim()?==?"")
223???????continue;
224??????sb.Append("\ttemplateBuilder.Append(\""?+?temp?+?"\\r\\n\");\r\n");
225?????}
226?????strReturn?=?sb.ToString();
227????}
228???}
229???return?strReturn;
230??}
231
232?
233
234??/**////?<summary>
235??///?解析特殊變量
236??///?</summary>
237??///?<returns></returns>
238??public?abstract?string?ReplaceSpecialTemplate(string?forumpath,string?skinName,string?strTemplate);
239?}
240
241
??? 基本上都是對正則式的使用,因為本人不是這方面的高手,所以就不多說了,相信開源之后大家拿
源碼和注釋一看便知:)
??? 這里需要說明的就是ReplaceSpecialTemplate(string forumpath,string skinName,....) 這個函
數,它的實現我們要到discuz.forum.dll中去找,這里為了方便,直接就將反射出來的代碼加上注釋貼
出來,大家一看便知:
?
?1public?class?ForumPageTemplate?:?PageTemplate?2{
?3
?4?/**////?<summary>
?5?///?解析特殊變量
?6?///?</summary>
?7?///?<param?name="skinName">皮膚名</param>
?8?///?<param?name="strTemplate">模板內容</param>
?9?///?<returns></returns>
10?public?override?string?ReplaceSpecialTemplate(string?forumpath,string?skinName,string?strTemplate)
11?{
12??Regex?r;
13??Match?m;
14??
15??StringBuilder?sb?=?new?StringBuilder();
16??sb.Append(strTemplate);
17??????r?=?new?Regex(@"({([^\[\]/\{\}='\s]+)})",?RegexOptions.IgnoreCase|RegexOptions.Multiline|RegexOptions.Compiled);
18??for?(m?=?r.Match(strTemplate);?m.Success;?m?=?m.NextMatch())?
19??{
20???if?(m.Groups[0].ToString()?==?"{forumversion}")
21???{
22????sb?=?sb.Replace(m.Groups[0].ToString(),?Utils.GetAssemblyVersion());
23???}
24???else?if?(m.Groups[0].ToString()?==?"{forumproductname}")
25???{
26????sb?=?sb.Replace(m.Groups[0].ToString(),?Utils.GetAssemblyProductName());
27???}
28??}
29
30??foreach(DataRow?dr?in?GetTemplateVarList(forumpath,skinName).Rows)
31??{
32???sb?=?sb.Replace(dr["variablename"].ToString().Trim(),?dr["variablevalue"].ToString().Trim());
33??}
34??return?sb.ToString();
35?}
36
37
38?/**////?<summary>
39?///?獲取模板內容
40?///?</summary>
41?///?<param?name="skinName">皮膚名</param>
42?///?<param?name="templateName">模板名</param>
43?///?<param?name="nest">嵌套次數</param>
44?///?<param?name="templateid">皮膚id</param>
45?///?<returns></returns>
46?public?override?string?GetTemplate(string?forumpath,string?skinName,?string?templateName,?int?nest,int?templateid)
47?{
48??return?base.GetTemplate(forumpath,skinName,templateName,nest,templateid);
49?}
50
51?/**////?<summary>
52?///?獲得模板變量列表
53?///?</summary>
54?///?<param?name="skinName">皮膚名</param>
55?///?<returns></returns>
56?public?static?DataTable?GetTemplateVarList(string?forumpath,string?skinName)
57?{
58??Discuz.Cache.DNTCache?cache?=?Discuz.Cache.DNTCache.GetCacheService();
59????????????????DataTable?dt?=?cache.RetrieveSingleObject("/Forum/"?+?skinName?+?"/TemplateVariable")?as?DataTable;
60
61??if(dt?!=?null)
62??{
63???return?dt;
64??}
65??else
66??{
67???DataSet?dsSrc?=?new?DataSet("template");
68???string[]?filename?=?new?string[1]?{Utils.GetMapPath(forumpath?+?"templates/"?+?skinName?+?"/templatevariable.xml")};
69????
70???if?(Utils.FileExists(filename[0]))
71???{
72?????????dsSrc.ReadXml(filename[0]);
73
74??????????????????????????????if?(dsSrc.Tables.Count?==?0)
75??????????????????????????????{
76?????????????????????????????????
77??????????????????????????????}
78???}
79???else
80???{
81???????
82???}
83
84????????????????????????cache.AddSingleObject("/Forum/"?+?skinName?+?"/TemplateVariable",?dsSrc.Tables[0],?filename);
85???return?dsSrc.Tables[0];
86??}
87?}?
88}
89
90
??? 相信看到這里,熟悉設計模式的朋友會看出來,這里用到了"Template Method"模式,因為這
種模式很簡單,就不多做介紹了,相關信息可以看一下GOF的那本書或到網上一搜便知。
??? 下面要說的就是上面的這個 ForumPageTemplate類目前所要實現的功能。因為模板中要被訂制
的東西有很多,而我們目前所搭建的功能只是為了生成和轉換時使用,當用戶有要替換的特殊變量
就會出現無法訂制的情況。所以才提供了這個類以便實現與模板有關的用戶訂制需求。當然目錄所
提供的功能只是簡單的替換而已,但并不排除以后隨著用戶口味的挑剔而進行升級擴展的可能。
??? 而用戶進行特殊變量定制也非常簡單,只要在上面所貼的后臺“模板列表”圖中的后面點擊相
應的“管理”鏈接之后就會看到下面的頁面,如圖:
????
????只要再點擊右下方的“模板變量列表”,即可以進入定制模板變量的頁面,如圖:
????
??? 大家只要進行相應操作設置即可。
??? 好了,關于模板機制的介紹,這里就先告一段落了。有問題的朋友可以在回復中進行交流和發
EMAIL給我(daizhj617595@126.com,daizhj@gmail.com,daizhj@discuz.com)。
??? 關鍵字:discuz,discuz!nt,設計模式,template,template mothod,daizhj,代震軍
???
轉載于:https://www.cnblogs.com/aaa6818162/archive/2009/05/18/1459387.html
總結
以上是生活随笔為你收集整理的Discuz!NT 模板机制分析(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 停止FMS3.5的Apache服务
- 下一篇: LR在安装和卸载问题上的一点总结(转帖)