# 一、完成工程案例、资讯中心页面渲染
# 1. 控制器 app/controller/api/template01/api.js
const pageType = [
'piclist', //图片列表展示
'newslist', //新闻列表展示
'mixlist', //图文混合列表展示
];
...
//其它页面
async ortherpage() {
const { ctx, app } = this;
//页面显示形式pageType
let _pageType = ctx.query.pageType;
//js判断数组中是否包含某个元素
if(!pageType.includes(_pageType)){
_pageType = pageType[0];
}
//传参获取分类id
let category_id = parseInt(ctx.params.category_id);
const data = await ctx.apiPage('News',{
category_id:category_id
});
//由于多次用到分类相关信息
let category = await ctx.model.Category.findByPk(category_id);
console.log('分类信息category',JSON.parse(JSON.stringify(category)));
await ctx.renderApi({
tempType: 'ortherpage',
data,
pageType:_pageType,
category,
}, 'api/template01/main_app.html');
}
# 2. 模版 app/view/api/template01/main_app.html
{% if tempType == 'ortherpage' %}
{% include "api/template01/_ortherpage.html" %}
{% endif %}
# 3. 模版 app/view/api/template01/_ortherpage.html
<!-- 内页广告图 -->
<div style="margin-top: 100px;">
<img src="/public/api/template01/static/image/neibg.jpg" style="width: 100%;height: auto;display: block;">
</div>
<!-- 栏目名称 -->
<div class="column-name flex justify-center">
<div class="column-name-div">
<!-- 图标 -->
<div class="icon-div">
<span class="iconfont icon-zhuye"></span>
</div>
<!-- 栏目名 -->
<span class="name">{{category.name}}</span>
</div>
</div>
{{pageType}}
{% if pageType == 'piclist' %}
{# 图片列表模式 #}
<!-- 页面内容 -->
<div class="page-content flex justify-center">
<div style="width: 1200px;" class="py-40 case-div">
<!-- 内容 -->
{% for item in data %}
<div class="list">
<!-- 图片 -->
<div>
<img src="{{item.attachment}}" title="{{item.name}}">
</div>
<!-- 标题 -->
<div class="text-center mt-2">
<a href="./case_detail.html" target="_blank" class="text-no-underline text-dark lines-1 display-block"
title="{{item.name}}">{{item.name}}</a>
</div>
</div>
{% endfor %}
<!-- 分页 -->
<div style="width: 100%;">
{# 安全起见,egg.js官方默认将代码过滤成字符串,这里我们采用过滤器进行解码 #}
{{ ctx.locals.apipageHtml | safe }}
</div>
</div>
</div>
{% endif %}
{% if pageType == 'newslist' %}
{# 新闻列表展示 #}
<!-- 页面内容 -->
<div class="page-content flex justify-center">
<div style="width: 1200px;" class="py-40">
<!-- 名称 -->
<div class="flex align-center">
<h4 class="mr-2 font-lger text-dark text-center pb-2"
style="flex:auto;">{{category.name}}</h4>
</div>
<!-- 内容 -->
{% if data.length > 0 %}
<ul class="news-ul">
{% for item in data %}
<li>
<a href="./news_detail.html">
<span class="mr-1">+</span>
<span>{{item.name}}</span>
<span class="time">{{item.create_time.split(' ')[0]}}</span>
</a>
</li>
{% endfor %}
</ul>
{% else %}
<div class="flex align-center justify-center"> <span>当前栏目管理员还没有上传数据!</span></span></div>
{% endif %}
<!-- 分页 -->
<div style="width: 100%;">
{# 安全起见,egg.js官方默认将代码过滤成字符串,这里我们采用过滤器进行解码 #}
{{ ctx.locals.apipageHtml | safe }}
</div>
</div>
</div>
{% endif %}
# 4. 扩展 app/extend/context.js
// 前端分页 -- 模版1分页样式
async apiPage(modelName, where = {}, options = {}) {
let modeldata = await this.apiModelData(modelName, where, options);
console.log('modeldata的数据',modeldata);
...
//如果当前就是第一页,就不存在上一页,禁用上一页按钮,下一页同理
let prevDisabled = (page <= 1) || (totalPage == 0) ? 'disabled' : '';
let nextDisabled = (page >= totalPage) || (totalPage == 0) ? 'disabled' : '';
let firstpage = (page == 1) || (totalPage == 0) ? 'disabled' : '';
let lastpage = (page == totalPage) || (totalPage == 0) ? 'disabled' : '';
...
}
# 5. 路由 app/router/api/template01/router.js
router.get('/api/template/01/cid/:category_id', controller.api.template01.api.ortherpage);
# 二、文章详情页数据渲染
# 1. 控制器 app/controller/api/template01/api.js
//数据详情页
async pageinfo(){
const { ctx, app } = this;
//页面显示形式pageType
let _pageType = ctx.query.pageType;
//js判断数组中是否包含某个元素
if(!pageType.includes(_pageType)){
_pageType = 'detail';
}
let id = parseInt(ctx.params.id);
let news = await ctx.model.News.findOne({
where:{
id,
status:1
}
});
console.log('新闻内容',JSON.parse(JSON.stringify(news)));
let category = await ctx.model.Category.findByPk(news.category_id);
//上一篇下一篇
const Op = this.app.Sequelize.Op;//拿Op,固定写法
const prevdata = await ctx.model.News.findOne({
where:{
id:{
[Op.lt]:id
},
category_id:news.category_id,
status:1
},
order:[['id','DESC']]
});
const nextdata = await ctx.model.News.findOne({
where:{
id:{
[Op.gt]:id
},
category_id:news.category_id,
status:1
},
order:[['id','ASC']]
});
await ctx.renderApi({
tempType: 'ortherpage',
news,
pageType:_pageType,
category,
ortherdata:{
prevdata,
nextdata
}
}, 'api/template01/main_app.html');
}
# 2. 路由 app/router/api/template01/router.js
router.get('/api/template/01/id/:id', controller.api.template01.api.pageinfo);
# 3. 模版 app/view/api/template01/_ortherpage.html
{# 信息详情 #}
{% if pageType == 'detail' %}
<!-- 页面内容 -->
<div class="page-content flex justify-center">
<div style="width: 1200px;" class="py-40">
<!-- 名称 -->
<div class="flex justify-between border-bottom"
style="align-items: baseline;">
<h4 class="mr-2 font-lger text-dark">{{news.name}}</h4>
<span class="font text-light-muted" style="width: 100px;">{{news.create_time.split(' ')[0]}}</span>
</div>
<!-- 内容 -->
<div>
{{news.maincontent | safe}}
</div>
<!-- 上一篇下一篇 -->
<ul class="prev-next">
{% if ortherdata and ortherdata.prevdata %}
<li>
<a href="#">
<span style="margin-right: 15px;color:#999999;">上一篇</span>
<span>{{ortherdata.prevdata.name}}</span>
<span>{{ortherdata.prevdata.create_time.split(' ')[0]}}</span>
</a>
</li>
{% endif %}
{% if ortherdata and ortherdata.nextdata %}
<li>
<a href="#">
<span style="margin-right: 15px;color:#999999;">下一篇</span>
<span>{{ortherdata.nextdata.name}}</span>
<span>{{ortherdata.nextdata.create_time.split(' ')[0]}}</span>
</a>
</li>
{% endif %}
</ul>
<!-- 返回按钮 -->
<div class="flex align-center justify-end my-5">
<a href="#"
class="py-3 px-5 text-white bg-info bg-hover-info">返回列表</a>
</div>
</div>
</div>
{% endif %}
# 三、工程案例、资讯中心等文章链接完善,返回列表功能完善
# 1. 控制器 app/controller/api/template01/api.js
...
//其它页面
async ortherpage() {
记得先修改扩展里:面前端分页 -- 模版1分页样式--apiPage函数返回值
return modeldata.data;
...
//如果分类里面只有一条数据,则直接转到新闻详情
if(data.count == 1){
let id = data.rows[0].id;
ctx.redirect(`/api/template/01/id/${id}?pageType=detail`);
return;
}
...
await ctx.renderApi({
...
data:data.rows,
...
}, 'api/template01/main_app.html');
}
...
//数据详情页
async pageinfo() {
...
//看一下该分类下有几篇文章,如果只有一篇,则不显示返回列表按钮
let categorynews = await ctx.model.News.findAndCountAll({
where:{
category_id:news.category_id,
status:1
},
// 主表查询字段限制
attributes:['id','name'],
});
console.log('该分类下有几篇文章',JSON.parse(JSON.stringify(categorynews)));
...
await ctx.renderApi({
...
ortherdata:{
...
categorynewsCount:categorynews.count,//分类下几篇文章
frompageType:ctx.query.frompageType //返回分类列表的分类页面类型
}
}, 'api/template01/main_app.html');
}
...
# 2. 模版 app/view/api/template01/_ortherpage.html
每个栏目的链接改一下
...
<!-- 标题 -->
<div class="text-center mt-2">
<a href="/api/template/01/id/{{item.id}}?pageType=detail&frompageType={{pageType}}" class="text-no-underline text-dark lines-1 display-block"
title="{{item.name}}">{{item.name}}</a>
</div>
...
<!-- 上一篇下一篇 -->
<li>
<a href="/api/template/01/id/{{ortherdata.prevdata.id}}?pageType=detail">
<span style="margin-right: 15px;color: #999999;">上一篇</span>
<span>{{ortherdata.prevdata.name}}</span>
<span>{{ortherdata.prevdata.create_time.split(' ')[0]}}</span>
</a>
</li>
<li>
<a href="/api/template/01/id/{{ortherdata.nextdata.id}}?pageType=detail">
<span style="margin-right: 15px;color: #999999;">下一篇</span>
<span>{{ortherdata.nextdata.name}}</span>
<span>{{ortherdata.nextdata.create_time.split(' ')[0]}}</span>
</a>
</li>
返回列表
<!-- 返回按钮 -->
{% if ortherdata.categorynewsCount > 1 %}
<div class="flex align-center justify-end my-5">
<a href="/api/template/01/cid/{{category.id}}?pageType={{ortherdata.frompageType}}"
class="py-3 px-5 text-white bg-info bg-hover-info">返回列表</a>
</div>
{% endif %}
# 四、处理网站导航栏及选中情况
# ① 获取导航栏数据,完成选中:工程案例、资讯中心
- 数据库分类表category新增字段(isnav是否是导航栏上的分类)、(categoryurl 链接地址)
category表 迁移文件 和 模型:
isnav: {
type: INTEGER(1),
allowNull: false,
defaultValue: 0,
comment: '该分类是否也是导航栏的栏目 0否 1是'
},
categoryurl: {
type: STRING,//不限定长度.默认varchar(255)
allowNull: true,
defaultValue: '',
comment: '分类链接地址'
},
记得数据库category表也要修改一下!
- 完成后台分类管理新增、修改界面和提交数据新增的两个字段,分类列表也要增加这两个字段展示
app/controller/admin/category.js
//分类列表页面
async index() {
//表头
columns: [
...
{
title: '是否是导航栏栏目',
key: 'isnav',
width: 200,//可选
class: 'text-center',//可选
hidekeyData: true,//是否隐藏key对应的数据
render(item) {
console.log('可用状态里面每个item', item);
let arr = [
{ value: 1, name: '是' },
{ value: 0, name: '否' },
];
let str = `<div class="btn-group btn-group-${item.id}">`;
for (let i = 0; i < arr.length; i++) {
str += `<button type="button" class="btn btn-light" data="${item.isnav}"
value="${arr[i].value}"
@click="changeBtnStatus('isnav','btn-group-${item.id}',${arr[i].value},${i},${item.id},'category','Category')">${arr[i].name}</button>`;
}
str += `</div>`;
return str;
}
},
{
title: '分类链接地址',
key: 'categoryurl',
class: 'text-center',//可选
},
...
]
}
//创建分类表单 async create()
//修改分类界面 async edit()
// 字段
fields: [
...
{
label: '分类链接地址',
type: 'text',
name: 'categoryurl',
placeholder: '请输入分类链接地址,选填',
},
...
]
//分类表单提交数据 async save()
//修改分类提交数据 async update()
//1.参数验证
categoryurl: {
type: 'string',
required: false,
defValue: '',
desc: '分类链接地址'
},
...
const { ...,categoryurl } = ctx.request.body;
...
category.categoryurl = categoryurl; 修改分类提交数据 async update()
...
categoryurl 分类表单提交数据 async save()
- 控制器 读取导航栏数据分发到模版页面
app/controller/api/template01/api.js
//导航栏数据
async nav(){
const { ctx, app } = this;
let nav = await ctx.model.Category.findAll({
where:{
isnav:1,
status:1
},
order:[
['order','asc']
]
});
return nav;
}
增加到各个方法里面
nav: await this.nav(), //导航栏数据
- 导航栏模版
app/view/api/template01/_header.html
<!-- 导航栏右边部分 导航内容部分 -->
<div class="right-div flex align-center ">
{# <a href="/api/template/01" class="active">网站首页</a>
<a href="/api/template/01/cid/5?pageType=newslist" >关于我们</a>
<a href="/api/template/01/cid/6?pageType=newslist" >资讯中心</a>
<a href="/api/template/01/cid/7?pageType=newslist" >主营业务</a>
<a href="/api/template/01/cid/8?pageType=piclist&limit=16" >工程案例</a>
<a href="/api/template/01/cid/9?pageType=newslist" >联系我们</a> #}
{# 可采用在控制器判断变量来设置哪个栏目选中,也可以用vue.js来处理,也可以用jquery来处理选中问题 #}
{% for item in nav %}
<a href="{{item.categoryurl if item.categoryurl else '/api/template/01/cid/' ~ item.id ~ '?pageType=newslist'}}"
dataid="{{item.id}}">{{item.name}}</a>
{% endfor %}
</div>
...
<script>
$(function(){
let url = location.href;
let cid = url.substr(0,url.indexOf('?'));
cid = cid.substring(cid.lastIndexOf('/') + 1);
console.log(cid);
$('#nav').find('a').each(function(index,element){
if($(element).attr('dataid') == cid){
$(element).addClass('active');
}
});
});
</script>
记得主模板引入jquery app/view/api/template01/main_app.html
<script src="/public/api/template01/static/js/jquery.1.11.3.min.js"></script>
关于jquery我们在上一个季度详细讲过了,jquery.js文件可以去下载上一个季度课程里面的文件, 也可以 https://www.bootcdn.cn/jquery/ (opens new window)
# ② 完成导航栏其他栏目的选中问题
- 路由
app/router/api/template01/router.js
//数据详情页
router.get('/api/template/01/id/:id/cid/:category_id', controller.api.template01.api.pageinfo);
- 模版 app/view/api/template01/_ortherpage.html
...
<a href="/api/template/01/id/{{item.id}}/cid/{{category.id}}?pageType=detail&frompageType={{pageType}}"
...
<!-- 上一篇下一篇 -->
<a href="/api/template/01/id/{{ortherdata.prevdata.id}}/cid/{{category.id}}?pageType=detail&frompageType={{ortherdata.frompageType}}">
<a href="/api/template/01/id/{{ortherdata.nextdata.id}}/cid/{{category.id}}?pageType=detail&frompageType={{ortherdata.frompageType}}">
...
- 控制器
app/controller/api/template01/api.js分类只有一条数据的跳转
//其它页面
async ortherpage() {
...
//如果分类里面只有一条数据,则直接转到新闻详情
if (data.count == 1) {
let id = data.rows[0].id;
ctx.redirect(`/api/template/01/id/${id}/cid/${category_id}?pageType=detail`);
return;
}
...
}
# 五、网站首页导航栏选中、及网站配置展示
- 路由
app/router/api/template01/router.js
module.exports = app => {
const { router, controller } = app;
//首页或前缀
const main_index = app.config.globalVar.template01.index;
//首页 '/api/template/01'
router.get(main_index, controller.api.template01.api.index);
//其它页面一般是分类页面
router.get(main_index + '/cid/:category_id', controller.api.template01.api.ortherpage);
//数据详情页
router.get(main_index + '/id/:id/cid/:category_id', controller.api.template01.api.pageinfo);
}
- 全局
config/config.default.js
//配置全局变量
config.globalVar = {
template01:{
index:'/api/template/01', //首页或前缀
}
};
- 控制器
app/controller/api/template01/api.js读取网站配置json文件和全局变量
//获取配置数据
async getsiteConfigJson() {
//先判断是否存在这个json文件或者文件夹
if (!fs.existsSync(paths.file)) {
return '';
} else {
let data = fs.readFileSync(paths.file, {
encoding: 'utf-8'
});
console.log(JSON.parse(data));
return JSON.parse(data)
}
}
await ctx.renderApi({
...
siteconfig:await this.getsiteConfigJson(), //网站配置
main_index: app.config.globalVar.template01.index, //首页或前缀
...
});
- 模版
app/view/api/template01/_header.html
<!-- 导航栏 -->
<div class="flex justify-center" id="nav"
index="{{main_index}}"
style="position: fixed;left: 0px;right: 0px;top: 0px;z-index: 1;background-color: #ffffff;">
<div style="width: 1200px;" class="flex justify-between align-center">
<!-- 导航栏的左边 logo图 -->
<div class="left-logo flex align-center">
<img src="/public/api/template01/static/image/logo.png" />
</div>
<!-- 导航栏右边部分 导航内容部分 -->
<div class="right-div flex align-center ">
{# <a href="/api/template/01" class="active">网站首页</a>
<a href="/api/template/01/cid/5?pageType=newslist">关于我们</a>
<a href="/api/template/01/cid/6?pageType=newslist">资讯中心</a>
<a href="/api/template/01/cid/7?pageType=newslist">主营业务</a>
<a href="/api/template/01/cid/8?pageType=piclist&limit=16">工程案例</a>
<a href="/api/template/01/cid/9?pageType=newslist">联系我们</a> #}
{% for item in nav %}
<a
href="{{item.categoryurl if item.categoryurl else main_index ~'/cid/'~item.id~'?pageType=newslist'}}"
dataid="{{item.id}}">
{{item.name}}</a>
{% endfor %}
</div>
</div>
</div>
<script>
$(function(){
let url = location.href;
let origin = location.origin;
let cid = url.substr(0,url.indexOf('?'));
cid = cid.substring(cid.lastIndexOf('/') + 1);
// console.log(cid);
$('#nav').find('a').each(function(index,element){
if($(element).attr('dataid') == cid){
$(element).addClass('active');
}
//首页选中
//console.log($('#nav').attr('index'));
//console.log(url.replace(origin,''));
//console.log($('#nav').attr('index'));
if($('#nav').attr('index') && $('#nav').attr('index') == url.replace(origin,'') && $(element).attr('href') == $('#nav').attr('index')){
$(element).addClass('active');
}
});
});
</script>
模版
app/view/api/template01/_ortherpage.html
替换/api/template/01为{ {main_index} }模版
app/view/api/template01/_bottom.html
<!-- 底部 -->
<div id="page_footer" class="flex justify-center py-5">
<div style="width: 1200px;" class="flex justify-between">
<!-- 左边 -->
<div class="flex align-center">
<!-- logo -->
<img src="/public/api/template01/static/image/footer_logo.png" style="width: 107px;height: 107px;">
<!-- 地址信息 -->
<div class="ml-2 text-light-muted">
<p>{{siteconfig.data[0].corporate_name}}</p>
<p>地址:{{siteconfig.data[0].address}}</p>
<p>
{{siteconfig.data[0].copyright}} {{siteconfig.data[0].icpNumber}}
</p>
</div>
</div>
<!-- 右边 -->
<div class="flex align-center">
<!-- 电话图标 -->
<img src="/public/api/template01/static/image/footer_tel.png" style="width: 56px;height: 56px;">
<!-- 电话 -->
<div class="ml-2 text-light-light-muted">
<p>业务咨询电话</p>
<strong class="font-max">{{siteconfig.data[0].tel}}</strong>
</div>
</div>
</div>
</div>
# 六、关于我们、联系我们页面单独处理
- 细节处理:看本节课的课程视频
- 引入不同的界面到
app/view/api/template01/_ortherpage.html
{% if ortherType == 'aboutus' %}
{% include "api/template01/_aboutus.html" %}
{% endif %}
{% if ortherType == 'contactus' %}
{% include "api/template01/_contactus.html" %}
{% endif %}
- 控制器
app/controller/api/template01/api.js在路由上新增字段进行判断,如:
http://127.0.0.1:7001/api/template/01/id/1/cid/5?pageType=detail&ortherType=aboutus
http://127.0.0.1:7001/api/template/01/cid/9?ortherType=contactus
ortherType: ctx.query.ortherType, //其他模块如联系我们关于我们
# 七、网站留言板提交留言到后台
- 用上个季度的留言板代码 替换 当前留言板代码
- 引入相应的js文件
- 写接口
app/controller/api/template01/api.js - 调试留言板
具体看本节课视频。