由于本人不是專業的前端,也沒人給我設計一個輕博客。所以我只能利用互聯網上的資源。 辛虧有了Bootstrap3,我也能冒充一下前端。
> 它山之石,可以攻玉
# 前端CSS框架選擇
本來還猶豫試試Amaze UI的jquery版, 但是Amaze UI 由于出來的晚,不是很完善,也沒有像 <http://expo.bootcss.com/> 這樣的案例展示墻,想參照自定義要費一番功夫。

然后幸運的是bootstrap 自帶了一個博客案列:


感覺上挺簡潔,也支持響應式。
# js類庫
- jquery 這是必須的,原生js不會,開發效率慢。jq的組件比較多,也比較熟。
- audiojs 用于音頻播放
- bootstrap-table 用于自己實現移植ueditor里音樂搜索功能
- jcrop 圖片裁剪庫,用于生成頭像
- jqnotifybar 用于做自定義提示
- tagsinput 實現發布頁面的標簽提示
- nprogress 用于ajax請求時的動態等待進度條
- plupload 一個html5上傳組件
- smalot-bootstrap-datetimepicker 日期選擇器 支持時間的選擇
- uploadify swf上傳插件,在OneThink和之前的項目里用爛了。
- ueditor 百度文本編輯器
- swipebox 圖片展示slidebox
# web組件的安裝
由于要用到這么多的組件,一個個去官網上下載太麻煩了。索性用了一下 [bower-一個Web的包管理工具](https://github.com/bower/bower)。這貨可以解決包依賴問題,雖然下下來的資源可能比你需要的多,因為是將項目框架倉庫整個git pull 下來。里面可能會有demo、tests和readme.md。
安裝首先要有node,這個去官網下載安裝就好。
然后 `npm install -g bower` 全局安裝這個命令就好了。
~~~
# install dependencies listed in bower.json
$ bower install
# install a package and add it to bower.json
$ bower install <package> --save
# install specific version of a package and add it to bower.json
$ bower install <package>#<version> --save
~~~
也可以卸載某個包
`$ bower uninstall <package-name>`
具體使用方法,我就不介紹了。大家可以谷歌百度。
當然,有的時候由于項目可能被墻的原因,大家可能下載不了某個包。這時候只能靠人力了。我一般是 “紅杏”翻墻訪問,然后把下載地址放到115或者百度云盤里離線下載(我的迅雷會員到期了,迅雷沒落后就不想充了)。
# 前端資源目錄
上面的swipebox 是我自己下的,ueditor是找了一個ThinkPHP整合版,所以手動放置了。
大家可以看下我的前端目錄就知道了:

一般我喜歡前端資源放Public里。然后 bower_components 是bower安裝的目錄。
* css 樣式目錄
* images圖片庫
* js 自定義js
* static 是手動安裝的js組件庫
html5shiv.js 和respond.js 是為了兼容性的,
think.js 是OneThink里,苗兒曾經寫過 js的 兼容TP U函數的js實現。還有一個setValue 表單賦值函數。
# 代碼實現
## 變量替換
前面我們找了一個 博客靜態頁面。
然后,我們TP就要把它套好,能正常訪問。
在套之前,我們先定義下模板常量,這樣方便我們在模板中使用資源路徑。
忘了交代項目目錄了:

主要是應用目錄 分了 Admin后臺,Api rest接口,Common 公共模塊,Home 前臺 。Uploads是上傳目錄。 test是單元測試目錄。用了多入口綁定。因此除了index.php 還有 admin.php、api.php。
README.md 項目介紹文檔。
在`/App/Home/Conf/config.php` 前臺配置里 配置上模板解析常量
~~~
<?php
return array(
/* 模板相關配置 */
'TMPL_PARSE_STRING' => array(
'__STATIC__' => __ROOT__ . '/Public/static',
'__BOWER__'=>__ROOT__. '/Public/bower_components',
'__IMG__' => __ROOT__ . '/Public/images',
'__CSS__' => __ROOT__ . '/Public/css',
'__JS__' => __ROOT__ . '/Public/js',
),
'SHOW_PAGE_TRACE'=>true,
);
~~~
然后把 `view-source:http://v3.bootcss.com/examples/blog/` chrome里右鍵查看那個博客的源碼 復制下來的代碼 先存到/App/Home/View/Index/index.html里,然后所有 資源文件的路徑替換掉。有的如
`http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js` 這種直接 粘貼地址欄里 訪問在右鍵保存到項目目錄里。
替換前:
~~~
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3個meta標簽*必須*放在最前面,任何其他內容都*必須*跟隨其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>Blog Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="http://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="blog.css" rel="stylesheet">
<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="../../assets/js/ie-emulation-modes-warning.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="http://cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
~~~
替換后:
~~~
<html>
<head>
<meta charset="UTF-8">
<title>Freelog - 自由的輕博客</title>
<script src="__BOWER__/jquery/dist/jquery.min.js"></script>
<script src="__BOWER__/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="__BOWER__/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="__CSS__/blog.css">
<link rel="stylesheet" href="__BOWER__/jqnotifybar/css/jquery.notifyBar.css">
<script type="text/javascript" src="__BOWER__/jqnotifybar/jquery.notifyBar.js"></script>
<script type="text/javascript" src="__JS__/common.js"></script>
<script type="text/javascript">
// var url = window.location.pathname + window.location.search;
// url = url.replace(/(\/(p)\/\d+)|(&p=\d+)|(\/(id)\/\d+)|(&id=\d+)|(\/(group)\/\d+)|(&group=\d+)/, "");
var url = '__SELF__';
var no_pic = '__PUBLIC__/images/no-cover.png';
(function(){
var ThinkPHP = window.Think = {
"ROOT" : "__ROOT__", //當前網站地址
"APP" : "__APP__", //當前項目地址
"PUBLIC" : "__PUBLIC__", //項目公共目錄地址
"DEEP" : "{:C('URL_PATHINFO_DEPR')}", //PATHINFO分割符
"MODEL" : ["{:C('URL_MODEL')}", "{:C('URL_CASE_INSENSITIVE')}", "{:C('URL_HTML_SUFFIX')}"],
"VAR" : ["{:C('VAR_MODULE')}", "{:C('VAR_CONTROLLER')}", "{:C('VAR_ACTION')}"]
}
})();
$(function(){
//單頁高亮
$('.navbar-nav li').removeClass('active');
$('a.blog-nav-item[href="'+url+'"]').parent().addClass('active');
})
</script>
<!-- Your site ends -->
<block name="style"></block>
</head>
~~~
后面所有的靜態資源路徑都這么解決。
## 模板繼承
前端頁面其實很多頁面風格一樣,只是變了內容區域或者,上下左右某塊區域的內容。
ThinkPHP為我們提供了模板繼承這個功能,讓我們將共同的部分定義成父模板的一個個塊,讓我們子模板繼承了以后,如果不用相應的block去替換,就可以獲取父模板里原有塊的內容,非常方便。
所以,我將之前的模板先 全部復制了 保存到 Index/base.html里。
然后,定義了一些區塊
~~~
<html>
<head>
<meta charset="UTF-8">
<title>Freelog - 自由的輕博客</title>
<script src="__BOWER__/jquery/dist/jquery.min.js"></script>
<script src="__BOWER__/bootstrap/dist/js/bootstrap.min.js"></script>
<link href="__BOWER__/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="__CSS__/blog.css">
<link rel="stylesheet" href="__BOWER__/jqnotifybar/css/jquery.notifyBar.css">
<script type="text/javascript" src="__BOWER__/jqnotifybar/jquery.notifyBar.js"></script>
<script type="text/javascript" src="__JS__/common.js"></script>
<script type="text/javascript">
var url = '__SELF__';
var no_pic = '__PUBLIC__/images/no-cover.png';
(function(){
var ThinkPHP = window.Think = {
"ROOT" : "__ROOT__", //當前網站地址
"APP" : "__APP__", //當前項目地址
"PUBLIC" : "__PUBLIC__", //項目公共目錄地址
"DEEP" : "{:C('URL_PATHINFO_DEPR')}", //PATHINFO分割符
"MODEL" : ["{:C('URL_MODEL')}", "{:C('URL_CASE_INSENSITIVE')}", "{:C('URL_HTML_SUFFIX')}"],
"VAR" : ["{:C('VAR_MODULE')}", "{:C('VAR_CONTROLLER')}", "{:C('VAR_ACTION')}"]
}
})();
$(function(){
//導航高亮
$('.navbar-nav li').removeClass('active');
$('a.blog-nav-item[href="'+url+'"]').parent().addClass('active');
})
</script>
<!-- Your site ends -->
<block name="style"></block>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top blog-masthead">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="javascript:;">Freelog</a>
</div>
<div class="blog-nav collapse navbar-collapse" id="example-navbar-collapse">
<ul class="nav navbar-nav">
<li><a class="blog-nav-item" href="{:U('/')}">首頁</a></li>
<?php if (is_login()): ?>
<li><a class="blog-nav-item" href="{:U('/mine/')}">我的文章</a></li>
<?php endif ?>
<li>
<form class="navbar-form navbar-right" id="search" method="GET" action="/Search" role="search">
<div class="form-group input-group">
<input type="text" name="kw" class="form-control" placeholder="輸入關鍵字搜索" value="{$kw|default=""}">
<span class="input-group-btn">
<button class="btn btn-default">
<span class="glyphicon glyphicon-search f20" aria-hidden="true"></span>
</button>
</span>
</div>
</form>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="javascript:;" role="button" aria-expanded="false"><if condition="is_login()">{:session('user.nickname')}</if></a></li>
<if condition="is_login()">
<li><a class="blog-nav-item" href="{:U('/user/profile')}">個人信息</a></li>
<li><a class="blog-nav-item" href="{:U('/user/logout')}" class="ajax-get">退出</a></li>
<else/>
<li><a class="blog-nav-item" href="{:U('/user/login')}">登錄</a></li>
<li><a class="blog-nav-item" href="{:U('/user/reg')}">注冊</a></li>
</if>
</ul>
</div>
</div>
</div>
<div class="container" id="main">
<block name="header">
<div class="blog-header">
<h1 class="blog-title">The Bootstrap Blog</h1>
<p class="lead blog-description">The official example template of creating a blog with Bootstrap.</p>
</div>
</block>
<div class="row">
<div class="col-sm-8 blog-main">
<block name="main"></block>
</div><!-- /.blog-main -->
<div class="col-sm-3 col-sm-offset-1 blog-sidebar">
<block name="sidebar"></block>
</div><!-- /.blog-sidebar -->
</div><!-- /.row -->
</div><!-- /.container -->
<footer class="blog-footer">
<p>Blog template built for <a href="http://getbootstrap.com">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.Modified by <a href="http://weibo.com/u/1342658313">@黑白世界4648</a></p>
<p>? {:date('Y', time())} Freelog. 由 Thinkphp 強力驅動.</p>
<p>
<a href="#">Back to top</a>
</p>
</footer>
<block name="script"></block>
</body>
</html>
~~~
- `<block name="style"></block>` 頁面自定義樣式區,
- `<block name="header"></block>` 博客標題區
- `<block name="main"></block>` 博客內容區
- `<block name="sidebar"></block>` 側邊欄區
- `<block name="script"></block>` 頁面自定義js腳本區
再將index.html 頁面改為繼承base模板的
~~~
<extend name="Index/base" />
<block name="header">
<div class="blog-header">
<h4>{$title|default=""}</h4>
</div>
</block>
<block name="main">
<volist name="list" id="post" key="post_k">
<assign name="tpl" value="$post.type"/>
<switch name="tpl">
<case value="text"><include file="Index/text" /></case>
<case value="picture"><include file="Index/picture" /></case>
<case value="music"><include file="Index/music" /></case>
<case value="video"><include file="Index/video" /></case>
</switch>
</volist>
<empty name="list">
<div class="text-center">
<img src="__IMG__/logo-grey.png" alt="" width="135">
<br><br>
對不起,沒有相應的文章
</div>
</empty>
{$_page}
</block>
<block name="sidebar">
<include file="Index/post_btn" />
<div class="sidebar-module sidebar-module-inset">
<h4>熱門標簽</h4>
<ul class="list-unstyled side-tracked-tag">
<volist name="tags" id="tag">
<li>
<a class="followed-tag clearfix" href="{:U('/')}?tag={$tag['title']}">
<span class="glyphicon glyphicon-tag" aria-hidden="true"></span>
<span class="">{$tag.title}</span>
</a>
</li>
</volist>
</ul>
</div>
<div class="sidebar-module">
<h4>歸檔</h4>
<ol class="list-unstyled">
<volist name="archive" id="vo">
<li><a href="{:U($vo['link'])}">{$vo.text}</a></li>
</volist>
</ol>
</div>
</block>
<block name="script">
<script type="text/javascript" src="__BOWER__/audiojs/audiojs/audio.min.js"></script>
<script src="__STATIC__/swipebox/js/jquery.swipebox.js"></script>
<link rel="stylesheet" href="__STATIC__/swipebox/css/swipebox.css">
<script type="text/javascript">
$(function(){
var single = audiojs;
single.events.ready(function() {
var a1 = single.createAll('', $('.single audio'));
});
//圖片燈箱
$( '.swipebox' ).swipebox();
})
</script>
</block>
~~~
上面區塊中,很多已經是最終現在的代碼了。先無視掉。
# 總結
前端實現方面 主要涉及了三個問題,資源選擇、資源引入、模板套用。
資源選擇 大家可以參考 [代碼家園](http://www.daimajiayuan.com/)、[最代碼](http://www.zuidaima.com/) 這些個站長資源站點,時不時自己收藏一些 類似于最好的jquery組件之類文章。
模板套用 要會用模板常量和模板繼承。后面還會講到模板include包含。
- 序
- 前言
- 內容簡介
- 目錄
- 基礎知識
- 起步
- 控制器
- 模型
- 模板
- 命名空間
- 進階知識
- 路由
- 配置
- 緩存
- 權限
- 擴展
- 國際化
- 安全
- 單元測試
- 拿來主義
- 調試方法
- 調試的步驟
- 調試工具
- 顯示trace信息
- 開啟調試和關閉調試的區別
- netbeans+xdebug
- Socketlog
- PHP常見錯誤
- 小黃鴨調試法,每個程序員都要知道的
- 應用場景
- 第三方登錄
- 圖片處理
- 博客
- SAE
- REST實踐
- Cli
- ajax分頁
- barcode條形碼
- excel
- 發郵件
- 漢字轉全拼和首字母,支持帶聲調
- 中文分詞
- 瀏覽器useragent解析
- freelog項目實戰
- 需求分析
- 數據庫設計
- 編碼實踐
- 前端實現
- rest接口
- 文章發布
- 文件上傳
- 視頻播放
- 音樂播放
- 圖片幻燈片展示
- 注冊和登錄
- 個人資料更新
- 第三方登錄的使用
- 后臺
- 微信的開發
- 首頁及個人主頁
- 列表
- 歸檔
- 搜索
- 分頁
- 總結經驗
- 自我提升
- 進行小項目的鍛煉
- 對現有輪子的重構和移植
- 寫技術博客
- 制作視頻教程
- 學習PHP的知識和新特性
- 和同行直接溝通、交流
- 學好英語,走向國際
- 如何參與
- 瀏覽官網和極思維還有看云
- 回答ThinkPHP新手的問題
- 嘗試發現ThinkPHP的bug,告訴官方人員或者push request
- 開發能提高效率的ThinkPHP工具
- 嘗試翻譯官方文檔
- 幫新手入門
- 創造基于ThinkPHP的產品,進行連帶推廣
- 展望未來
- OneThink
- ThinkPHP4
- 附錄