通过组件的方式实现文章列表,达到重复利用的目的。其他页面需要文章列表的时候只需要调用组件就可以了。
1、创建文章列表自定义组件目录
frontend下的widgets 表示存放自定义组件的目录,widgets下的post表示文章列表组件。以后有新的自定义组件只需参照文章列表组件的结构,将其放在frontend/widgets下即可。
views下的index.php为组件获取数据后的数据渲染页面
PostWidget.php为自定义组件类

2、创建文章列表组定义组件类
<?php
namespace frontend\widgets\post;
/**
* 自定义文章列表组件
*/
use common\models\PostsModel;
use frontend\models\PostsForm;
use yii\base\Widget;
use yii\data\Pagination;
use yii\helpers\Url;
use Yii;
class PostWidget extends Widget
{
//文章列表的标题
public $title = '';
//显示条数
public $limit = 6;
//是否显示更多
public $more = true;
//是否显示分页
public $page = false;
public function run()
{
//获取当前页,若没有则默认当前页为1
$curPage = Yii::$app->request->get('page',1);
//数据条件,获取已发布数据
$cond = ['=','is_valid',PostsModel::IS_VALID];
//获取文章列表数据
$res = PostsForm::getList($cond, $curPage, $this->limit);
//设置文章列表属性
$result['title'] = $this->title?$this->title: '最新文章';
$result['more'] = Url::to(['posts/index']);
$result['body'] = $res['data']?$res['data']:[];
//判断是否显示分页
if ($this->page){
$pages = new Pagination(['totalCount'=>$res['count'],'pageSize'=>$res['pageSize']]);
}
return $this->render('index',['data'=>$result]);
}
}文章列表自定义组件到到这也就基本实现了,不过具体的数据获取方法还没有实现,所以接下来就要实现这些获取数据的方法。


2、组件中数据获取方法的实现
①getList方法实现 (PostForm 中)
/**
* 获取文章列表
* @param $cond
* @param int $curPage
* @param int $pageSize
* @param array $orderBy
* @return mixed
*/
public static function getList($cond, $curPage = 1, $pageSize = 5, $orderBy = ['id'=> SORT_DESC])
{
$model = new PostsModel();
//构造查询语句
//查询字段
$select = ['id', 'title', 'summary', 'label_img', 'cat_id', 'user_id',
'user_name', 'is_valid', 'created_at', 'updated_at'];
$query = $model->find()
->select($select)
->where($cond)
->with('relate.tag','extend')
->orderBy($orderBy);
//获取分页数据
//因为其他地方也有可能获取列表数据,所以单独用一个获取分页数据的方法来获取文章列表数据
//为了实现getPage方法的共用性,我们在BaseModel中实现这个方法
$res = $model -> getPage($query, $curPage, $pageSize);
//格式化数据(主要格式化tag数据)
$res['data'] = self::_formatList($res['data']);
//把获取到的数据返回出去
return $res;
}
②实现数据格式化方法(PostForm 中)
/**
* 格式化数据
* @param $data
* @return mixed
*/
public static function _formatList($data)
{
foreach ($data as &$list){
$list['tags'] = [];
if (isset($list['relate']) && !empty($list['relate'])){
foreach ($list['relate'] as $lt){
$list['tags'][] = $lt['tag']['tag_name'];
}
//格式化后把原有的tag关联数据删除
unset($list['relate']);
}
}
return $data;
}
③在BaseModel中实现获取分页数据方法getPage
public function getPage($query, $curPage = 1, $pageSize = 10, $search = null)
{
//判断是否搜索,若搜索还需筛选数据
if ($search)
$query = $query->andFilerWhere($search);
//获取总条数 若总条数为0,返回初始配置,若不返回数据会报错
$data[ 'count'] = $query->count();
if (!$data['count']){
return ['count'=>0, 'curPage'=>$curPage, 'pageSize'=>$pageSize,
'start'=>0, 'end=>0', 'data'=>[]
];
}
//当前页计算 防止人为输入的页面不存在
$curPage = (ceil($data['count'])/$pageSize<$curPage)?ceil($data['count'])/$pageSize<$curPage:$curPage;
//当前页,将数据放入data中返回
$data['curPage'] = $curPage;
//每页显示条数
$data['pageSize'] = $pageSize;
//数据起始
$data['start'] = ($curPage-1)*$pageSize+1;
//数据结束
$data['end'] = (ceil($data['count'])/$pageSize) == $curPage?$data['count']:$curPage*$pageSize;
//数据获取
$data['data'] = $query->offset(($curPage-1)*$pageSize)
->limit($pageSize)
->asArray()
->all();
return $data;
}
数据已经获取到,接下来把数据渲染到自定义文章列表组件的渲染页面index.php
<?php
use yii\helpers\Url;
use yii\widgets\LinkPager;
?>
<div class="panel">
<div class="panel-title box-title">
<span><?=$data['title']?></span>
<?php if($this->context->more):?>
<span class="pull-right"><a href="<?=$data['more']?>" class="font-12">更多»</a></span>
<?php endif;?>
</div>
<div class="new-list">
<?php foreach ($data['body'] as $list):?>
<div class="panel-body border-bottom">
<div class="row">
<div class="col-lg-4 label-img-size">
<a href="#" class="post-label">
<img src="<?=($list['label_img']?\Yii::$app->params['upload_url'].$list['label_img']:\Yii::$app->params['default_label_img'])?>" alt="<?=$list['title']?>">
</a>
</div>
<div class="col-lg-8 btn-group">
<h1><a href="<?=Url::to(['post/detail','id'=>$list['id']])?>"><?=$list['title']?></a></h1>
<span class="post-tags">
<span class="glyphicon glyphicon-user"></span><a href="<?=Url::to(['member/index','id'=>$list['user_id']])?>"><?=$list['user_name']?></a>
<span class="glyphicon glyphicon-time"></span><?=date('Y-m-d',$list['created_at'])?>
<span class="glyphicon glyphicon-eye-open"></span><?=isset($list['extend']['browser'])?$list['extend']['browser']:0?>
<span class="glyphicon glyphicon-comment"></span><a href="<?=Url::to(['post/detail','id'=>$list['id']])?>"><?=isset($list['extend']['comment'])?$list['extend']['comment']:0?></a>
</span>
<p class="post-content"><?=$list['summary']?></p>
<a href="<?=Url::to(['post/detail','id'=>$list['id']])?>"><button class="btn btn-warning no-radius btn-sm pull-right">阅读全文</button></a>
</div>
</div>
<div class="tags">
<?php if(!empty($list['tags'])):?>
<span class="fa fa-tags"></span>
<?php foreach ($list['tags'] as $lt):?>
<a href="#"><?=$lt?></a>,
<?php endforeach;?>
<?php endif;?>
</div>
</div>
<?php endforeach;?>
</div>
<?php if($this->context->page):?>
<div class="page"><?=LinkPager::widget(['pagination' => $data['page']]);?></div>
<?php endif;?>
</div>
不过这里有两个数据需要配置 'upload_url' (图片路径前缀),'default_label_img',当文章没有缩率图时显示的默认图片
'upload_url' => 'http://frontend.yii2.com', 'default_label_img' => '/statics/images/default.png',

文章列表自定义组件就算完成了,接下来就是调用,文章列表渲染页调用,其他页面调用文章列表自定义组件列表方法也是一样的
<?php use frontend\widgets\post\PostWidget; use yii\base\Widget; ?> <?=PostWidget::widget()?>

文章列表页需要添加的css样式(放到site.css页面即可),若不加css样式最后的页面显示可能会有点丑。
.panel-body h1 {
font-size: 18px;
height: 30px;
line-height: 30px;
margin: 0;
overflow: hidden;
}
.post-label {
background-color: #fff;
border: 1px solid #ddd;
display: block;
line-height: 1.42857;
padding: 4px;
transition: border 0.2s ease-in-out 0s;
border-radius: 0;
margin-bottom: 5px;
position: relative;
}
.post-label > img {
margin-left: auto;
margin-right: auto;
display: block;
height: 150px;
width: 100%;
}
.post-tags {
color: #999;
font-size: 12px;
}
.post-tags span {
margin-right: 4px;
}
.post-tags a {
color: #999;
}
.tags {
font-size: 12px;
margin-left: 2px;
}
.font-12 {
font-size: 12px;
}最后的文章列表调用效果:

