## 數據獲取
像一般應用一樣,我們首頁就是Index/index 方法。
看看代碼:
~~~
public function index($page = 1){
$this->lists($page);
$this->display();
}
~~~
怎么這么短,參數綁定了一個分頁參數page。
這個Common模塊里設置了一下:
`'VAR_PAGE'=>'page',`
因為考慮到默認的p參數可能以后會被占用。page更語義化點。
列表數據的邏輯主要集中在lists方法里。
So,我們來一探它的究竟。
~~~
public function lists($page = 1){
$map = array();
$list_row = I('r', 10);
$postModel = D('Post');
//tag搜索
$tags = I('get.tag');
if($tags){
$ids = $postModel->where(" FIND_IN_SET('{$tags}',tags)")->getField('id', true);
$this->assign('title', "標簽 <i>{$tags}</i> 下的文章");
if(!empty($ids))
$map['id'] = array('in',$ids);
}
//關鍵詞搜搜
if(I('get.kw')){
$kw = trim(I('get.kw'));
$map['title'] = array('like',"%{$kw}%");
$like_id = $postModel->where("content LIKE '%{$kw}%' OR description LIKE '%{$kw}%'")->getField('id', true);
if($like_id)
$map['id'] = array('in', $like_id);
}
//區分所有人和本人發布的文章
if( false !== strpos(__SELF__, 'mine') && is_login()){
$map['member_id'] = session('user.uid');
}
//歸檔搜索
if(isset($_GET['year']) && isset($_GET['month'])){
$year = CONTROLLER_NAME;
$month = ACTION_NAME;
$map['_string'] = "`deadline` LIKE binary('{$year}-{$month}%')";
}
$map['deadline'] = array('elt', datetime());
$this->assign('list', $postModel->where($map)->page($page, $list_row)->order('`deadline` DESC')->select());
/* 分頁 */
$total = $postModel->where($map)->count();
$page = new \Think\Page($total, $list_row);
$page->rollPage = 5;
$page->setConfig('prev','上一頁');
$page->setConfig('next','下一頁');
$page->setConfig('theme','<div class="pager">%UP_PAGE% %DOWN_PAGE%</div>');
$p = $page->show();
$this->assign('_page', $p? $p: '');
//tag列表
$this->assign('tags', M('Tags')->order('count DESC')->select());
//獲取歸檔
$list = $postModel->where($map)->order('`deadline` DESC,`id` DESC')->select();
$date = $time = array();
foreach ($list as $key => $value) {
if($value['deadline'])
$time[] = date('F Y', strtotime($value['deadline']));
}
$time = array_unique($time);
foreach ($time as $key => $value) {
$date[] = array(
'text'=> $value,
'link'=> date('Y/m', strtotime($value))
);
}
$this->assign('archive', $date);
}
~~~
~~~
$map = array();
$list_row = I('r', 10);
$postModel = D('Post');
~~~
先定義一個查詢用的map數組變量。
并且每頁展示數量獲取r get或post參數。并且默認值為10。先這樣寫,支持以后通過傳參控制每頁顯示多少篇文章。
定義一個變量存儲實例化Post的模型。
然后就開始查數據并賦值模板變量$list:
~~~
$map['deadline'] = array('elt', datetime());
$this->assign('list', $postModel->where($map)->page($page, $list_row)->order('`deadline` DESC')->select());
~~~
默認查詢是發布文章截止發布日期時間過后,也就是當前時間大于截止發布時間的文章。
然后用了查詢里的page 方法傳 $page 頁數和 $list_row 每頁數量 并按發布截止時間降序 分頁后查詢。
這里用了一個技巧,直接賦值 而不是先定義一個變量等于查詢結果。多一個變量就多占一部分內存,而且這個變量后面我們不會再操作和用到。
而且$postModel 因為后面要用到。所以我們用變量緩存Post 模型實例。并且,因為我們查詢需要用到Post模型的類方法,所以用D。如果只是簡單查詢,最好還是用M函數。
主要列表數據查完后,就是分頁和其他額外數據查詢。
分頁后面會講。
額外數據標簽查詢。
也是一句話:
~~~
//tag列表
$this->assign('tags', M('Tags')->order('count DESC')->select());
~~~
然后我們看下index模板,
~~~
<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>
~~~
繼承Index/base 父模板,header block部分提供一個默認為空的標題。
~~~
<block name="header">
<div class="blog-header">
<h4>{$title|default=""}</h4>
</div>
</block>
~~~
然后 main 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>
~~~
邏輯就是 遍歷 list變量,然后 通過assign 模板標簽臨時賦值tpl為文章類型,本來想通過這個類型動態include的模板的,結果發現不行。include 標簽的file屬性不支持動態變量。
如果你想動態加載的模板個數有限, 就像我這樣switch 后 case里include寫死的模板吧。
然后還通過empty 標簽 考慮了沒數據list的樣式。
可愛的小鹿:

這也是搜索不到數據的呈現。
各個文章類型的,前面講發布時順帶說過部分代碼,
現在只說明一個類型文本。
~~~
<div class="blog-post text">
<present name="post.title"><h2 class="blog-post-title">{$post.title}</h2></present>
<p class="blog-post-meta">{$post.update_at|friendly_datetime} by <a href="#">{$post.author}</a></p>
<section class="blog-post-content">
{$post.content|htmlspecialchars_decode}
</section>
<section>
<neq name="Think.const.CONTROLLER_NAME" value="Post">
<a href="{:U('/Post/'.$post['id'])}" class="more" target="_blank">未完,繼續閱讀→</a>
<?php if (is_login() && is_login() == $post['member_id']): ?>
<a href="/api.php/post?id={$post.id}" class="ajax-delete confirm">刪除</a>
<?php endif ?>
<br>
<br>
</neq>
{$post.tags|get_tag}
</section>
</div>
~~~
基本容器都會帶上各自類型的類名,如文本就是text,以此類推。
然后就是 更新時間,已經發布者昵稱加空間鏈接。然后就是內容顯示,有的類型是描述字段,注意最新版tp,i函數默認用htmlspecialchars過濾了 讀出來必須htmlspecialchars_decode。否則看到的是html標簽。
如這樣:

接下來就是空間文章的權限操作顯示,并且在詳情頁時沒有這塊的顯示。
通過neq 標簽+控制器常量區分
`<neq name="Think.const.CONTROLLER_NAME" value="Post"`
然后里面比詳情頁就多了 “查看更多” 、“刪除”鏈接。
然后是標簽顯示:
`{$post.tags|get_tag} `
get_tag函數也簡單:
~~~
/**
* 獲取標簽的顯示
*/
function get_tag($tags, $link = true){
if($link && $tags){
$tags = explode(',', $tags);
$link = array();
foreach ($tags as $value) {
$link[] = '<a href="'. U('/') . '?tag='.$value.'"><span class="label label-info">' . $value . '</span></a>';
}
return join($link,' ');
}else{
return $tags? $tags : '';
}
}
~~~
需要生成帶鏈接標簽時,分割,然后拼上url參數后join 空格。如果不要url就直接返回字段。
- 序
- 前言
- 內容簡介
- 目錄
- 基礎知識
- 起步
- 控制器
- 模型
- 模板
- 命名空間
- 進階知識
- 路由
- 配置
- 緩存
- 權限
- 擴展
- 國際化
- 安全
- 單元測試
- 拿來主義
- 調試方法
- 調試的步驟
- 調試工具
- 顯示trace信息
- 開啟調試和關閉調試的區別
- netbeans+xdebug
- Socketlog
- PHP常見錯誤
- 小黃鴨調試法,每個程序員都要知道的
- 應用場景
- 第三方登錄
- 圖片處理
- 博客
- SAE
- REST實踐
- Cli
- ajax分頁
- barcode條形碼
- excel
- 發郵件
- 漢字轉全拼和首字母,支持帶聲調
- 中文分詞
- 瀏覽器useragent解析
- freelog項目實戰
- 需求分析
- 數據庫設計
- 編碼實踐
- 前端實現
- rest接口
- 文章發布
- 文件上傳
- 視頻播放
- 音樂播放
- 圖片幻燈片展示
- 注冊和登錄
- 個人資料更新
- 第三方登錄的使用
- 后臺
- 微信的開發
- 首頁及個人主頁
- 列表
- 歸檔
- 搜索
- 分頁
- 總結經驗
- 自我提升
- 進行小項目的鍛煉
- 對現有輪子的重構和移植
- 寫技術博客
- 制作視頻教程
- 學習PHP的知識和新特性
- 和同行直接溝通、交流
- 學好英語,走向國際
- 如何參與
- 瀏覽官網和極思維還有看云
- 回答ThinkPHP新手的問題
- 嘗試發現ThinkPHP的bug,告訴官方人員或者push request
- 開發能提高效率的ThinkPHP工具
- 嘗試翻譯官方文檔
- 幫新手入門
- 創造基于ThinkPHP的產品,進行連帶推廣
- 展望未來
- OneThink
- ThinkPHP4
- 附錄