[TOC] # 模板制作快速入门 模板的制作并非难事,只要你写好了HTML和CSS,嵌套模板就非常简单了,你无需了解标签的内部结构,你只要会使用,模板就能迅速完成。这篇文章只简单的介绍了常用标签的使用方法,希望能带你进入模板的世界。^_^ 本篇文章以Emlog的默认模板为例,您可以打开默认模板default边看边学习。该模板所在的路径为 /content/templates/default,每个模板都是一个单独的文件夹,文件夹以模板名字命名。通过后台上传安装的模板都保存在这个目录下。 进入该目录后,我们可以看到有许多文件,别犯愁,我们将在下文一一介绍。 ## 模板文件结构说明 | 文件名 | 作用 | 必须 | | --- | --- | --- | | images文件夹 | 存放模板所需图片 | 否 | | preview.jpg | 在后台模板选择界面显示的模板预览图,300×225 jpg格式。 | 否 | | 404.php | 自定义404页面未找到时的报错页面 | 否 | | header.php | 头部页面文件 | 是 | | footer.php | 底部页面文件 | 否 | | log_list.php | 显示日志列表内容 | 否 | | echo_log.php | 显示日志内容 | 否 | | module.php | 模板公共代码,包含侧边widgets、评论、引用、编辑等,该文件是模板最核心的模块。 | 否 | | page.php | 自定义的页面内容的模板。 | 否 | | side.php | 模板侧边栏文件,如制作单栏模板则该文件不是必须的。 | 否 | | t.php | 显示emlog系统自带的微博(碎语)内容。 | 否 | ## 公共代码分析 > 通过预览整个模板中的各个文件,你会发现以下代码同时存在于多个文件中,这些代码分别有以下用途: if(!defined('EMLOG_ROOT')) {exit('error!');} 此行代码存在于模板目录下的每个php文件起始部分(事实上为了安全起见,该行代码也在admin目录下的几乎所有php文件起始部分存在),其作用是防止代码所在的php脚本被直接访问执行。 require_once View::getView('side'); require_once View::getView('footer'); 这两行代码存在于log_list.php、echo_log.php、page.php、t.php里面,其作用是调用模板文件夹下的side.php和footer.php的代码到当前文件的当前位置。View是emlog的模板视图控制器,View::getView('文件名','文件后缀')将返回当前模板安装路径下对应的文件。getView函数的第二个参数为缺省参数,在不传入值的情况下,将默认作为.php文件后缀返回文件路径。 ## header.php ### 开头注释内容是模板信息,该信息显示在模板选择界面 ``` /* Template Name:模板名称 Description:模板介绍描述 Version:模板版本 ForEmlog:适用版本 Author:模板作者 Author Url:作者或模板发布的URL Sidebar Amount:标记该模板有几个侧边栏,一般为1,有些模板有两个侧边栏则标记2。这样可以在后台widgets里识别管理 */ ``` ### 编码 打开这个文件,见到的第一个php代码就是: ~~~ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> ~~~ 调用默认的编码,现在最经常用的大都是utf-8吧。所以我通常是直接写成utf-8,省去php处理时间。 ### 页面标题 ~~~ <title><?php echo $site_title; ?></title> ~~~ 通常情况下直接复制使用,如果你没有时间的话。 ### 导入样式 ~~~ <link href="<?php echo TEMPLATE_URL; ?>style.css" rel="stylesheet" type="text/css" /> ~~~ 其中style.css是样式文件相对模板目录的路径和文件名。 ### 其它HTML头部信息 ~~~ <?php doAction('index_head'); ?> ~~~ 别忘了这句,前台头部扩展,它关系到增加前台css样式、加载js以及插件的正常使用。 ### 页面导航 ~~~ <?php blog_navi();?> ~~~ 它定义在了module.php中,使用缓存循环输出导航数据。 ``` global $CACHE; $navi_cache = $CACHE->readCache('navi'); ``` ### 网站名称 ~~~ <?php echo BLOG_URL; ?>//网站的首页地址 <?php echo $blogname; ?>//网站名称 <?php echo $bloginfo; ?>//网站的一些简短描述、介绍 ~~~ ### 站内搜索 ~~~ <form name="keyform" method="get" action="<?php echo BLOG_URL; ?>index.php"> <input name="keyword" type="text" /> </form> ~~~ 当你的文章很多很多,这个搜索就必不可少。 ### 一些模板公共代码 ``` if(!defined('EMLOG_ROOT')) {exit('error!');}//该行代码同样存在于其它模板文件中,为防止该文件被直接执行。 require_once View::getView('module'); $site_title//站点标题 $site_key//关键字 $site_description//输出博客设置的摘要 BLOG_URL//博客首页的URL TEMPLATE_URL//模板文件夹的URL,用于加载模板内的css、js及其他内容 Option::get('blogname')//使用Option配置类获取数据表options中的配置,此处获取的是博客名 <?php echo $curpage == CURPAGE_HOME ? 'current' : 'common';?> //判断当前是否首页,是则给导航加current类,用于表现当前位置。 <?php if($istwitter == 'y'):?><?php endif;?>//如后台设置在前台显示碎语,则输出…….中的内容。 <?php echo $curpage == CURPAGE_TW ? 'current' : 'common';?> //判断当前URL是否为微语并选择加类名。 <?php foreach ($navibar as $key ⇒ $val):?><?php endforeach;? >//输出自定义页面的链接 ``` ## index.php ### 显示文章 ~~~ <?php if (!empty($logs)){ foreach($logs as $value){ ?> <div>$value['logid']</div> <?php } } ?> ~~~ 进入文章循环,输出文章,剥开html代码,一句一句介绍 | 类型 | 代码 | | --- | --- | | 文章所在的连接 | Url::log($value['logid']) | |文章标题|$value['log_title']| |文章作者ID|$value['author']| |文章作者地址|Url::author($value['author'])| |文章的发布日期,格式可参考[PHP日期格式](http://cn.php.net/manual/zh/function.date.php "http://cn.php.net/manual/zh/function.date.php")|date('Y-n-j', $value['date'])| |文章所在分类|blog_sort($value['logid'])//blog_sort在model.php中自己定义| |文章评论数|$value['comnum']| |文章内容|$value['log_description']| 好了,文章显示结束,别忘了结束循环。 ### 文章分页 ~~~ <?php echo $page_url;?> ~~~ 文章输出结束后别忘了增加分页,至此,index.php的常见内容结束,应该不糊涂吧。 ### 一些模板公共代码 ~~~ <?php doAction('index_loglist_top');?>//文章列表顶部挂载点加入。 $value['logid']//该变量为当前日志的id <?php topflg($value['top']); ?>//显示置顶标记,该函数位于模板module.php内。 <?php echo $value['log_url']; ?>//输出日志URL <?php blog_author($value['author']);?>//输出日志的作者,该函数位于模板module.php内。 <?php editflg($value['logid'],$value['author']); ?>//当管理员或作者登陆时显示“编辑”链接,该函数位于模板module.php内。 <?php blog_att($value['logid']); ?>//如日志有附件则输出附件,该函数位于模板module.php内。 <?php blog_tag($value['logid']); ?>//输出日志的标签,该函数位于模板module.php内。 <?php echo $value['tbcount'];?>//输出当前日志的引用量 <?php echo $value['views']; ?>//输出当前日志的浏览量 <?php echo $page_url;?>//显示当前列表页的翻页功能。 <?php include View::getView('side'); include View::getView('footer');?>//加入侧边栏及加入页脚。 ~~~ ## footer.php ``` <a href="https://www.tongleer.com">同乐儿</a>//以示对同乐儿的支持 <?php echo BLOG_URL; ?>rss.php//RSS地址 Option::EMLOG_VERSION//获得版本号。 $icp//获得后台设置的ICP备案号。 <?php doAction('index_footer'); ?>//页脚底部挂载点加入。 ``` ## echo_log.php 该文件功能函数与列表页一致,但参数有区别,注意区分。 $logid 该变量为当前日志的id ~~~ <?php topflg($top); ?>//显示置顶标记,该函数位于模板module.php内。 <?php echo $log_title; ?>//输出日志标题。 <?php blog_author($author); ?>//输出日志的作者,该函数位于模板module.php内。 <?php echo date('Y-n-j G:i l', $date); ?>//输出日志发布时间,参数'Y-n-j G:i l'用于定义日期格式。 <?php blog_sort($logid); ?>//输出日志所属的分类,该函数位于模板module.php内。 <?php editflg($logid,$author); ?>//当管理员或作者登陆时显示“编辑”链接,该函数位于模板module.php内。 <?php echo $log_content; ?>//输出日志全文内容。 <?php blog_att($logid); ?>//如日志有附件则输出附件,该函数位于模板module.php内。 <?php blog_tag($logid); ?>//输出日志的标签,该函数位于模板module.php内。 <?php echo $comnum;?>//日志页显示评论数 <?php echo $tbcount; ?>//日志页显示引用数 <?php echo $views; ?>//日志页显示浏览量 <?php doAction('log_related', $logData); ?>//相关日志的挂载点,与3.x版本不同,4.0带第二参数。 <?php neighbor_log($neighborLog);?>//输出邻近,就是上一篇及下一篇,该函数位于模板module.php内。 <?php blog_trackback($tb, $tb_url, $allow_tb); ?>//输出该日志被引用的信息列表,与3.x不同注意区分。 <?php blog_comments($comments); ?>//输出该日志评论列表,与3.x不同注意区分。 <?php blog_comments_post($logid,$ckname,$ckmail,$ckurl,$verifyCode,$allow_remark); ?>//输出发表评论框,与3.x不同注意区分。 ~~~ ## page.php > 该文件写法与echo_log.php类似,不再重复。 ## t.php > 与之前相同的内容不再重复。 ~~~ <?php echo $avatar;?>//输出头像。 <?php echo $author; ?>// 输出作者名。 <?php echo $val['t'];?>//输出位微语内容。 <?php echo DYNAMIC_BLOGURL; ?>//根据当前url输出博客地址,主要用于js,解决跨域问题。 <?php echo $tid;?>//输出微语所在数据库中的id号。 <?php echo $val['date'];?>//发布微语的时间。 $reply_code//其值为‘n’或‘y’,后台设置是否启用碎语回复验证码。 <?php echo $rcode;?>//输出验证码。 ~~~ ## 404.php > 用于自定义404页面的模板。 ## side.php > 侧边栏,主要负责根据后台widgets设置信息输出侧边栏内容。建议该文件内代码保持不变,主要代码如下: ``` <?php $widgets = !empty($options_cache['widgets1']) ? unserialize($options_cache['widgets1']) : array(); doAction('diff_side'); foreach ($widgets as $val) { $widget_title = @unserialize($options_cache['widget_title']); $custom_widget = @unserialize($options_cache['custom_widget']); if(strpos($val, 'custom_wg_') === 0) { $callback = 'widget_custom_text'; if(function_exists($callback)) { call_user_func($callback, htmlspecialchars($custom_widget[$val]['title']), $custom_widget[$val]['content']); } }else{ $callback = 'widget_'.$val; if(function_exists($callback)) { preg_match("/^.*\s\((.*)\)/", $widget_title[$val], $matchs); $wgTitle = isset($matchs[1]) ? $matchs[1] : $widget_title[$val]; call_user_func($callback, htmlspecialchars($wgTitle)); } } } ?> ``` ## module.php > 模板公共代码,包含侧边widgets、评论、引用、编辑等。 该文件由若干函数组成,被博客前台文件调用,可在内自定义函数实现更多功能。 如在自定义函数内调用emlog缓存时,假设读取user缓存信息,则形如: global $CACHE; $user_cache = $CACHE->readCache('user'); 如需要操作数据库,则形如: $DB = Database::getInstance(); $res = $DB->query($sql);。 ### 个人资料模块 ``` function widget_blogger($title){ global $CACHE; $user_cache = $CACHE->readCache('user'); …… } ``` ### 日历模块 ``` <?php function widget_calendar($title){?> <div class="layui-row layui-col-space15" id="calendar"></div> <script>sendinfo('<?php echo Calendar::url(); ?>','calendar');</script> <?php }?> ``` ### 标签模块 ``` function widget_tag($title){ global $CACHE; $tag_cache = $CACHE->readCache('tags'); …… } ``` ### 分类模块 ``` function widget_sort($title){ global $CACHE; $sort_cache = $CACHE->readCache('sort'); …… } ``` ### 最新微语模块 ``` function widget_twitter($title){ global $CACHE; $newtw_cache = $CACHE->readCache('newtw'); $istwitter = Option::get('istwitter'); …… } ``` ### 最新评论模块 ``` function widget_newcomm($title){ global $CACHE; $comment_cache = $CACHE->readCache('comment'); …… } ``` ### 最新文章模块 ``` function widget_newlog($title){ global $CACHE; $newlog_cache = $CACHE->readCache('newlog'); …… } ``` ### 热门文章模块 ``` function widget_hotlog($title){ $DB = Database::getInstance(); $index_hotlognum = Option::get('index_hotlognum'); $Log_Model = new Log_Model(); $randLogs = $Log_Model->getHotLog($index_hotlognum); …… } ``` ### 随机文章模块 ``` function widget_random_log($title){ $DB = Database::getInstance(); $index_randlognum = Option::get('index_randlognum'); $Log_Model = new Log_Model(); $randLogs = $Log_Model->getRandLog($index_randlognum); …… } ``` ### 搜索模块 ``` <?php function widget_search($title){ ?> <form name="keyform" method="get" action="<?php echo BLOG_URL; ?>index.php"> <input name="keyword" type="text" /> </form> <?php }?> ``` ### 归档模块 ``` function widget_archive($title){ global $CACHE; $record_cache = $CACHE->readCache('record'); …… } ``` ### 自定义组件模块 ``` function widget_custom_text($title, $content){ …… } ``` ### 链接模块 ``` function widget_link($title){ global $CACHE; $link_cache = $CACHE->readCache('link'); …… } ``` ### 评论列表示例 ~~~ <?php function blog_comments($comments){ extract($comments); if($commentStacks): ?> <a name="comments"></a> <p class="comment-header"><b></b></p> <?php endif; ?> <?php $isGravatar = Option::get('isgravatar'); foreach($commentStacks as $cid): $comment = $comments[$cid]; $comment['poster'] = $comment['url'] ? '<a href="'.$comment['url'].'" target="_blank">'.$comment['poster'].'</a>' : $comment['poster']; ?> <div class="media-item comment" id="comment-<?php echo $comment['cid']; ?>"> <a name="<?php echo $comment['cid']; ?>"></a> <?php if($isGravatar == 'y'): ?><div class="avatar media-item-left"><img class="img-xs" src="<?php echo getGravatar($comment['mail']); ?>" /></div><?php endif; ?> <div class="media-text comment-info"> <a href="javascript:;"><?php echo $comment['poster']; ?></a> <mdall class="comment-time"><?php echo $comment['date']; ?></mdall> <a class="comment-reply" href="#comment-<?php echo $comment['cid']; ?>" onclick="commentReply(<?php echo $comment['cid']; ?>,this)">回复</a> <div class="comment-content"><?php echo $comment['content']; ?></div> </div> </div> <?php blog_comments_children($comments, $comment['children']); ?> <?php endforeach; ?> <div id="pagenavi"> <?php echo $commentPageUrl;?> </div> <?php }?> ~~~ ### 子评论列表示例 ``` <?php function blog_comments_children($comments, $children){ $isGravatar = Option::get('isgravatar'); foreach($children as $child): $comment = $comments[$child]; $comment['poster'] = $comment['url'] ? '<a href="'.$comment['url'].'" target="_blank">'.$comment['poster'].'</a>' : $comment['poster']; ?> <div class="media-item comment comment-children" id="comment-<?php echo $comment['cid']; ?>"> <a name="<?php echo $comment['cid']; ?>"></a> <?php if($isGravatar == 'y'): ?><div class="avatar media-item-left"><img class="img-xs" src="<?php echo getGravatar($comment['mail']); ?>" /></div><?php endif; ?> <div class="media-text comment-info"> <a href="javascript:;"><?php echo $comment['poster']; ?></a> <mdall class="comment-time"><?php echo $comment['date']; ?></mdall> <?php if($comment['level'] < 4): ?><a class="comment-reply" href="#comment-<?php echo $comment['cid']; ?>" onclick="commentReply(<?php echo $comment['cid']; ?>,this)">回复</a><?php endif; ?> <div class="comment-content"><?php echo $comment['content']; ?></div> </div> </div> <?php blog_comments_children($comments, $comment['children']);?> <?php endforeach; ?> <?php }?> ``` ### 评论输入表单示例 ~~~ <?php function blog_comments_post($logid,$ckname,$ckmail,$ckurl,$verifyCode,$allow_remark){ if($allow_remark == 'y'): ?> <div id="comment-place"> <div class="comment-post" id="comment-post"> <div class="cancel-reply" id="cancel-reply" style="display:none"><a href="javascript:void(0);" onclick="cancelReply()" class="layui-btn layui-btn-primary">取消回复</a></div> <p class="comment-header"><b></b><a name="respond"></a></p> <form class="layui-form" method="post" name="commentform" action="<?php echo BLOG_URL; ?>index.php?action=addcom" id="commentform"> <input type="hidden" name="gid" value="<?php echo $logid; ?>" /> <?php if(ROLE == ROLE_VISITOR): ?> <p> <input class="layui-input" type="text" name="comname" maxlength="49" value="<?php echo $ckname; ?>" size="22" tabindex="1" placeholder="昵称"> </p> <p> <input class="layui-input" type="text" name="commail" maxlength="128" value="<?php echo $ckmail; ?>" size="22" tabindex="2" placeholder="邮件地址 (选填)"> </p> <p> <input class="layui-input" type="text" name="comurl" maxlength="128" value="<?php echo $ckurl; ?>" size="22" tabindex="3" placeholder="个人主页 (选填)"> </p> <?php endif; ?> <p><textarea class="layui-textarea" name="comment" id="comment" rows="10" tabindex="4" required="required" placeholder="评论内容"></textarea></p> <p><?php echo $verifyCode; ?> <input class="layui-btn layui-btn-primary" type="submit" id="comment_submit" value="发表评论" tabindex="6" /></p> <input type="hidden" name="pid" id="comment-pid" value="0" size="22" tabindex="1"/> </form> </div> </div> <?php endif; ?> <?php }?> ~~~ ## 前台模板部分挂载点一览 > doAction('index_footer'); 页脚底部挂载点 > doAction('index_loglist_top'); 首页日志列表顶部挂载点 > doAction('log_related', $logData); 相关日志挂载点 > doAction('diff_side'); 侧边栏挂载点 ## 结束语 OK,这篇简短的入门讲解结束了,希望你看着不累,同时能对Emlog的模板系统了解一二,这样文章的目的也就达到了,针对当前文章的不明白的地方,欢迎到论坛提出问题。谢谢。