62. 分类话题列表
简介
在本节里,我们实现点击顶部导栏里的『话题分类』显示该分类的话题列表。
需求分解
『话题分类』功能有助于话题的归类,方便用户按照话题分类查阅信息,本章节中,我们将开发以下功能:
- 根据分类显示话题列表;
- 分类名称作为列表页面标题;
- 在顶部导航栏添加分类列表入口;
- 给导航栏添加选中状态。
数据模型
首先,我们修改 Topic::minePaginate
方法,让它支持按分类搜索功能。
application/common/model/Topic.php
<?php
.
.
.
class Topic extends Model
{
.
.
.
/**
* 分页查询方法
* @Author zhanghong(Laifuzi)
* @DateTime 2019-06-20
* @param array $params 请求参数
* @param integer $page_rows 每页显示数量
* @return [type] 分页查询结果
*/
public static function minePaginate($param = [], $per_page = 20)
{
$self = self;
foreach ($param as $name => $value) {
switch ($name) {
case 'category_id':
if($value > 0){
$self = $self->where($name, $value);
}
break;
}
}
$paginate = $self->paginate($per_page);
return $paginate;
}
}
控制器
- 首先,因为我们要在导航栏显示出所有分类,所以
Base
控制器在初始化时需要查询出所有分类信息:
application/index/controller/Base.php
<?php
namespace app\index\controller;
.
.
.
use app\common\model\Category as CategoryModel;
class Base extends Controller
{
protected function initialize()
{
if(!request()->isAjax()){
$site = ConfigModel::siteSetting();
$this->assign('site', $site);
$flash_names = ['success', 'info', 'danger'];
foreach ($flash_names as $key => $name) {
if(Session::has($name)){
$flash[$name] = Session::pull($name);
}
}
$this->assign('flash', $flash);
$categories = CategoryModel::order('id', 'ASC')->all();
$this->assign('categories', $categories);
}
}
}
- 接着,使用命令行创建分类控制器:
$ php think make:controller index/Category
因为我们在分类控制器只需要展示话题列表,所以只需要 read
方法,完整代码如下。
application/index/controller/Category.php
<?php
namespace app\index\controller;
use think\Request;
use app\common\model\Topic as TopicModel;
use app\common\model\Category as CategoryModel;
class Category extends Base
{
public function read(Request $request, $id)
{
$category = CategoryModel::find($id);
$this->assign('category', $category);
$param['category_id'] = $id;
$paginate = TopicModel::minePaginate($param);
$this->assign('paginate', $paginate);
// 使用topic/index页面渲染输出
return $this->fetch('topic/index');
}
}
路由
在配置文件里定义控制方法访问路由规则:
route/route.php
<?php
.
.
.
// 话题管理
Route::get('topic', 'topic/index')->name('topic.index');
Route::get('category/<id>', 'category/read')->name('category.read');
助手函数
我们需要定义一个助手函数实现——当用户访问的是 category.read
页面时对应的分类菜单项是选中状态,否则 「话题」菜单项是选中状态。
application/index/common.php
<?php
.
.
.
/**
* 顶部导航是否选中样式
* @Author zhanghong(Laifuzi)
* @DateTime 2019-02-23
* @param string $route_name 路由路径
* @param array $param 判断参数
* @return [type] [description]
*/
function navbar_class($route_name, $param = [])
{
$request = request();
try{
// 使用 request的 controlelr 和 action 方法生成当前访问页面路由路径
$ctr_name = $request->controller(true);
$act_name = $request->action(true);
$page_route = $ctr_name . '/' .$act_name;
}catch(\Exception $e){
// 当 request 不存在 controller 或 action 方法时,使用routeInfo生成当前访问页面路由路径
$route_info = $request->routeInfo();
if(empty($route_info) || empty($route_info['route'])){
$page_route = '';
}else{
$page_route = $route_info['route'];
}
}
if(empty($page_route)){
// 当前访问页面路由路径为空
return '';
}else if($route_name != $page_route){
// 当前路由路径 和 菜单项路由路径不相等
return '';
}
if(empty($param)){
// 当前路由路径 和 菜单项路由路径相等 并且没有判断参数
// 菜单项必然是选中状态
return 'active';
}
$is_active = true;
// 只有当所有 判断参数 都相等时菜单项才是选中状态
foreach ($param as $name => $value) {
$param_value = $request->param($name);
$pm[$name] = $param_value;
if($param_value != $value){
$is_active = false;
break;
}
}
if($is_active){
return 'active';
}else{
return '';
}
}
视图模板
- 首先,我们在顶部导航栏里添加所有分类列表页入口,并且使用助手方法
navbar_class
给所有菜单项添加上选中状态判断。
application/index/view/layout/_header.html
.
.
.
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
<li class="nav-item <?php echo(navbar_class('topic/index')) ?>">
<a class="nav-link" href="{:url('[topic.index]')}">话题</a>
</li>
{volist name="categories" id="category"}
<li class="nav-item <?php echo(navbar_class('category/read', ['id' => $category->id])) ?>">
<a class="nav-link" href="{:url('[category.read]', ['id' => $category->id])}">{$category->name}</a>
</li>
{/volist}
</ul>
.
.
.
- 接下来,为了实现「分类名称作为列表页面标题」,我们需要在话题列表页显示出分类名称:
application/index/view/topic/index.html
.
.
.
<div class="col-lg-9 col-md-9 topic-list">
{if(isset($category) && !empty($category))}
<div class="alert alert-info" role="alert">
{$category->name} :{$category->description}
</div>
{/if}
<div class="card ">
.
.
.
</div>
</div>
.
.
.
- 最后,我们还需要给列表里的话题分类添加
category.read
路由链接。
application/index/view/topic/_list.html
.
.
.
<a class="text-secondary" href="{:url('[category.read]', ['id' => $topic->category_id])}" title="{$topic->category->name}">
<i class="far fa-folder"></i>
{$topic->category->name}
</a>
.
.
.
样式优化
我们用浏览器访问话题列表页并点击某个分类的链接进入分类列表页,看到分类列表页样式有些混乱。
这是因为在 app.css 里使用主模板中定义的路由 CSS 类名称。
application/index/view/layout/main.html
.
.
.
<body>
<div id="app" class="<?php echo(route_class()); ?>">
.
.
.
因为 topic.index' 和
category.read两个方法使用同一个模板,当页面路由名称已变为
category.read时对应的 CSS 类名已变为
category-read-page` 。所以我们需要在样式表中新添加选择器。
public/static/assets/index/css/app.css'
.
.
.
/* Topic Index Page */
.topic-index-page .topic-list .nav > li > a,
.category-read-page .topic-list .nav > li > a{
position: relative;
display: block;
padding: 5px 14px;
font-size: 0.9em;
}
.topic-index-page .topic-list a,
.category-read-page .topic-list a{
color: #444444;
}
.topic-index-page .topic-list .meta,
.category-read-page .topic-list .meta{
font-size: 0.9em;
color: #b3b3b3;
}
.topic-index-page .topic-list .meta a,
.category-read-page .topic-list .meta a{
color: #b3b3b3;
}
.topic-index-page .topic-list .badge,
.category-read-page .topic-list .badge{
background-color: #d8d8d8;
}
.topic-index-page .topic-list hr,
.category-read-page .topic-list hr{
margin-top: 12px;
margin-bottom: 12px;
border: 0;
border-top: 1px solid #dcebf5;
}
.
.
.
效果展示
Git 版本控制
下面把代码纳入到版本管理里:
$ git add -A
$ git commit -m "分类话题列表"
推荐文章: