
以下是PbootCMS的主要目录结构及其作用:
目录/文件 | 说明 |
|---|---|
/apps | 应用目录,包含主要业务逻辑 |
/apps/admin | 后台管理应用 |
/apps/home | 前台应用 |
/apps/api | API接口应用 |
/apps/common | 公共目录 |
/config | 配置文件目录 |
/config/config.php | 系统主配置文件 |
/config/database.php | 数据库配置文件 |
/config/route.php | 路由配置文件 |
/core | 框架核心文件 |
/template | 模板文件目录 |
/static | 静态资源目录 |
/runtime | 运行时缓存目录 |
index.php | 前台入口文件 |
admin.php | 后台入口文件 |
下面通过一个实际案例演示如何在PbootCMS中创建自定义产品展示页面,包括控制器、模板和路由配置。
在/apps/home/controller/目录下创建ProductController.php文件:
<?php
// /apps/home/controller/ProductController.php
/**
* 产品展示控制器
* 演示PbootCMS二次开发流程
*/
class ProductController extends Controller
{
/**
* 产品列表页
*/
public function index()
{
// 接收参数并过滤
$page = get('page', 'int') ?: 1;
$keywords = get('keywords', 'vars');
// 构建查询条件
$where = array();
if ($keywords) {
$where['title'] = ['like', '%' . $keywords . '%'];
}
// 设置每页显示数量
$pageSize = 10;
// 调用模型获取数据
$data = $this->model->content->getList($where, $page, $pageSize, 'date desc');
// 分配数据到模板
$this->assign([
'productList' => $data->data, // 产品列表数据
'page' => $data->page, // 分页数据
'keywords' => $keywords // 搜索关键词
]);
// 显示模板
$this->display('product_list.html');
}
/**
* 产品详情页
*/
public function detail()
{
// 获取产品ID
$id = get('id', 'int');
if (!$id) {
error('产品ID不能为空!');
}
// 读取产品详情
$product = $this->model->content->getDetail($id);
if (!$product) {
error('产品不存在!');
}
// 获取相关产品(使用tags标签关联)
$relatedWhere = [
'tags' => $product->tags,
'id' => ['neq', $id] // 排除当前产品
];
$relatedProducts = $this->model->content->getList($relatedWhere, 1, 6, 'random');
// 分配数据到模板
$this->assign([
'product' => $product,
'relatedProducts' => $relatedProducts->data
]);
// 显示模板
$this->display('product_detail.html');
}
/**
* 产品搜索API接口
* 返回JSON格式数据
*/
public function search()
{
// 只允许AJAX访问
if (!is_ajax()) {
json(0, '非法访问!');
}
$keywords = get('keywords', 'vars');
$page = get('page', 'int') ?: 1;
$pageSize = 12;
$where = array();
if ($keywords) {
$where['title'] = ['like', '%' . $keywords . '%'];
}
$data = $this->model->content->getList($where, $page, $pageSize, 'date desc');
// 返回JSON数据
json(1, 'success', [
'list' => $data->data,
'page' => $data->page->toArray(),
'keywords' => $keywords
]);
}
}
?>在/template/default/目录下创建产品列表模板product_list.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>产品列表 - {pboot:sitetitle}</title>
<meta name="keywords" content="{pboot:sitekeywords}">
<meta name="description" content="{pboot:sitedescription}">
<link rel="stylesheet" href="/static/css/product.css">
</head>
<body>
{include file='header.html'}
<div class="container">
<div class="breadcrumb">
当前位置:<a href="{pboot:sitelink}">首页</a> > 产品中心
</div>
<!-- 搜索框 -->
<div class="search-box">
<form action="{content:link}" method="get">
<input type="text" name="keywords" value="{content:keywords}" placeholder="输入产品关键词">
<button type="submit">搜索</button>
</form>
</div>
<!-- 产品列表 -->
<div class="product-list">
{pboot:list scode=2 num=12 page=1 order='date desc'}
<div class="product-item">
<div class="product-image">
<a href="[list:link]">
<img src="[list:ico]" alt="[list:title]" onerror="this.src='/static/images/default.jpg'">
</a>
</div>
<div class="product-info">
<h3><a href="[list:link]">[list:title]</a></h3>
<p class="product-desc">[list:description lenth=50]</p>
<div class="product-meta">
<span class="date">[list:date style=Y-m-d]</span>
<span class="visits">浏览:[list:visits]</span>
</div>
</div>
</div>
{/pboot:list}
</div>
<!-- 分页 -->
<div class="pagination">
{content:page}
</div>
</div>
{include file='footer.html'}
<script src="/static/js/product.js"></script>
</body>
</html>在/template/default/目录下创建产品详情模板product_detail.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{content:title} - {pboot:sitetitle}</title>
<meta name="keywords" content="{content:keywords}">
<meta name="description" content="{content:description}">
<link rel="stylesheet" href="/static/css/product.css">
</head>
<body>
{include file='header.html'}
<div class="container">
<div class="breadcrumb">
当前位置:<a href="{pboot:sitelink}">首页</a> >
<a href="{sort:link}">{sort:name}</a> >
{content:title}
</div>
<!-- 产品详情 -->
<div class="product-detail">
<div class="detail-header">
<h1>{content:title}</h1>
<div class="meta">
<span>发布时间:{content:date style=Y-m-d H:i}</span>
<span>浏览次数:{content:visits}</span>
<span>作者:{content:author}</span>
</div>
</div>
<div class="detail-content">
{content:content}
</div>
<!-- 多图展示 -->
{pboot:if({content:pics})}
<div class="product-gallery">
<h3>产品图集</h3>
<div class="gallery-list">
{pboot:list pics={content:pics}}
<div class="gallery-item">
<img src="[list:value]" alt="产品图片">
</div>
{/pboot:list}
</div>
</div>
{/pboot:if}
</div>
<!-- 相关产品 -->
<div class="related-products">
<h3>相关产品</h3>
<div class="related-list">
{pboot:list scode={sort:scode} num=6 filter=id!={content:id} order=random}
<div class="related-item">
<a href="[list:link]">
<img src="[list:ico]" alt="[list:title]">
<span>[list:title]</span>
</a>
</div>
{/pboot:list}
</div>
</div>
</div>
{include file='footer.html'}
</body>
</html>在/config/route.php文件中添加自定义路由规则:
<?php
// /config/route.php
return array(
// 默认路由规则
'default' => 'home/Index/index',
// 产品模块路由
'product.html' => 'home/Product/index', // 产品列表页
'product/detail/:id' => 'home/Product/detail', // 产品详情页
'api/product/search' => 'home/Product/search', // 产品搜索API
// 更多自定义路由...
);
?>在/static/css/目录下创建product.css样式文件:
/* /static/css/product.css */
.product-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}
.product-item {
border: 1px solid #eaeaea;
border-radius: 8px;
overflow: hidden;
transition: transform 0.3s ease;
}
.product-item:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.product-image img {
width: 100%;
height: 200px;
object-fit: cover;
}
.product-info {
padding: 15px;
}
.product-info h3 {
margin: 0 0 10px 0;
}
.product-info h3 a {
color: #333;
text-decoration: none;
}
.product-desc {
color: #666;
line-height: 1.6;
margin-bottom: 10px;
}
.product-meta {
display: flex;
justify-content: space-between;
color: #999;
font-size: 12px;
}在/static/js/目录下创建product.js脚本文件:
// /static/js/product.js
// 产品搜索功能
document.addEventListener('DOMContentLoaded', function() {
// 实时搜索建议
const searchInput = document.querySelector('input[name="keywords"]');
if (searchInput) {
let timeout = null;
searchInput.addEventListener('input', function() {
clearTimeout(timeout);
timeout = setTimeout(function() {
const keywords = searchInput.value.trim();
if (keywords.length > 1) {
fetchSearchSuggestions(keywords);
}
}, 500);
});
}
// 产品图片懒加载
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
});
// 获取搜索建议
async function fetchSearchSuggestions(keywords) {
try {
const response = await fetch('/api/product/search?keywords=' + encodeURIComponent(keywords));
const data = await response.json();
if (data.code === 1) {
displaySearchSuggestions(data.data.list);
}
} catch (error) {
console.error('搜索请求失败:', error);
}
}
// 显示搜索建议
function displaySearchSuggestions(products) {
// 实现搜索建议显示逻辑
console.log('搜索建议:', products);
}PbootCMS提供了强大的模板标签系统,可以方便地调用各种数据:
<!-- 调用指定栏目的内容列表 -->
{pboot:list scode=1,2,3 num=5 order='date desc' isrecommend=1}
<div class="news-item">
<a href="[list:link]">[list:title]</a>
<span class="date">[list:date style=Y-m-d]</span>
</div>
{/pboot:list}
<!-- 调用站点信息 -->
站点名称:{pboot:sitetitle}
站点关键词:{pboot:sitekeywords}
站点描述:{pboot:sitedescription}
<!-- 调用导航菜单 -->
{pboot:nav}
<a href="[nav:link]">[nav:name]</a>
{/pboot:nav}在控制器中进行数据库操作:
// 在控制器方法中使用模型
public function customMethod()
{
// 使用内容模型
$contentModel = $this->model->content;
// 复杂查询
$where = [
'scode' => [1, 2, 3], // 栏目编码
'title' => ['like', '%关键词%'],
'visits' => ['>', 100]
];
$list = $contentModel->getList($where, 1, 10, 'visits desc');
// 自定义SQL查询(谨慎使用)
$sql = "SELECT * FROM ay_content WHERE scode IN (1,2,3) ORDER BY date DESC LIMIT 10";
$result = $this->model->query($sql);
}在/config/config.php中开启调试模式:
// /config/config.php
return array(
'debug' => true, // 开启调试模式
'error_level' => E_ALL, // 错误报告级别
// 其他配置...
);{pboot:cache}标签缓存不常变化的内容原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。