`标签处,此处可以理解为``中的内容,为页面的主要内容。
3. `
{% endblock %}
{% block content %}
{{article.detail}}
{% endblock %}
{%block script%}
{% endblock %}
```
此处需要注意1点:
md的内容先通过模板,渲染在一个隐藏的div中。之后,通过`editormd`动态渲染出来。
### 发表文章
#### article.tpl 发表文章
我们创建`app/view/article/article.tpl`文件:
```
{% extends "parent.tpl" %}
{% block head %}
Markdown Editor
{% endblock %}
{% block content %}
{% endblock %}
{% block script %}
{% endblock %}
```
此处需要注意1点:
ajax默认是不重定向的,所以当保存成功,我们需要返回文章的访问url,在回调函数里重定向。
### 后端代码
#### ArticleController
我们创建`app/controller/article.js`文件:
```
const Controller = require('egg').Controller;
class ArticleController extends Controller {
async list() {
const ctx = this.ctx;
const articleList = await ctx.service.article.list();
await ctx.render('article/list.tpl', { list: articleList });
}
async detail(){
const ctx = this.ctx;
const queryRes = await ctx.service.article.detail(ctx.params.id);
ctx.logger.info(queryRes);
await ctx.render('article/detail.tpl', { article: queryRes[0] });
}
}
module.exports = ArticleController;
```
#### EditController
我们创建`app\controller\edit.js`文件:
```
const Controller = require('egg').Controller;
const fs = require('mz/fs');
class EditController extends Controller{
async editHtm(){
await this.ctx.render('article/edit.tpl');
}
async save(){
const ctx = this.ctx;
const article = ctx.request.body.article;
article.id = ctx.helper.uuid();
article.url = '/article/'+article.id+'.htm';
article.author = ctx.session.user.username;
const nowTime = new Date();
article.create_time = nowTime;
article.update_time = nowTime;
const result = await ctx.service.article.save(article);
if (result) {
ctx.body = {flag:'1',msg:'保存成功',url:article.url}
}else {
ctx.body = {flag:'0',msg:'保存失败'}
}
}
async uploadPic(){
const { ctx } = this;
const file = ctx.request.files[0];
let filenameNew = ctx.helper.uuid() +'.'+ file.filename.split('.').pop();
let filepathNew = this.config.baseDir+'\\app\\public\\mdPic\\'+filenameNew;
//把临时文件剪切到新目录去
await fs.rename(file.filepath, filepathNew);
//按editormd要求格式返回
ctx.body = {
success : 1, //0表示上传失败;1表示上传成功
message : "上传成功",
url : filepathNew.split(this.config.baseDir+'\\app')[1] //上传成功时才返回
}
}
}
module.exports = EditController;
```
此处需要注意1点:
1. `uoloadPic`方法主要用于md编辑器的图片上传。
### ArticleService
我们创建`app/service/article.js`文件:
```
const Service = require('egg').Service;
class ArticleService extends Service {
async list() {
const sql = "SELECT url,title,author,update_time FROM article WHERE invisible = 0";
const list =await this.app.mysql.query(sql);
return list;
}
async detail(id = 1){
const sql = "SELECT title,detail,author,update_time FROM article WHERE id = ?";
return await this.app.mysql.query(sql,[id])
}
async save(article = {}){
const res = await this.app.mysql.insert('article',article);
return res.affectedRows === 1;
}
}
module.exports = ArticleService;
```
### router.js
我们往 `app/router.js`中添加一下内容:
```
router.get('/edit.htm',controller.edit.editHtm);
router.get('/article/:id.htm',controller.article.detail);
router.get('/articleList.htm', controller.article.list);
router.post('/edit/save',controller.edit.save);
router.post('/edit/uploadPic',controller.edit.uploadPic);
```
#编辑文章
编辑文章,首先得把文章原先内容获取到,然后放在编辑页,给用户展现出一个“半成品”的状态,可以重新保存文章。
## 页面设计
### 我的文章页面
![](/contentImages/image/jianshu/5979029-2db1c69aac0b3a25.png)
### 编辑页面
![](/contentImages/image/jianshu/5979029-516a5cd7013e894d.png)
## 功能设计
1. 我的文章页标题前显示是否保密,标题后有编辑按钮
2. 点击编辑按钮,进入编辑页面可重新编辑文章
## 前端代码
### myarticle.tpl 我的文章页
我们创建`/app/view/article/myarticle.tpl`页面:
```
{% extends "parent.tpl" %}
{% block head %}
我的文章
{% endblock %}
{% block content %}
我的文章
{% for item in list %}
-
-
{{helper.formatInvisible(item.invisible)}}
{{ item.title }}
编辑
- {{item.author}} 最后更新于 {{helper.formatTime(item.update_time)}}
{% endfor %}
{% endblock %}
```
此处需要注意1点:
1. `helper.formatInvisible`与`helper.formatTime`两个方法的作用是***格式化***后端返回的参数。当然,你也可以在后端代码执行这些逻辑,不过我更倾向于后端代码尽量精简。**格式化应当归属于前端范畴。**如果说模板的渲染属于后端逻辑,那当我没说= =。
>关于helper用法:https://eggjs.org/zh-cn/basics/objects.html#helper
### helper.js
```
const moment = require('moment');
//时间格式化
exports.formatTime = time => moment(time).format('YYYY-MM-DD HH:mm:ss');
exports.formatInvisible = invisible => invisible===1 ? '保密':'';
```
### modify.tpl 编辑文章页
我们创建`/app/view/article/modify.tpl`页面:
```
{% extends "parent.tpl" %}
{% block head %}
编辑文章
{% endblock %}
{% block content %}
{% endblock %}
{% block script %}
{% endblock %}
```
## 后端代码
### ArticleController
我们添加以下内容:
```
async myarticle(){
const ctx = this.ctx;
const articleList = await ctx.service.article.getArticleByAuthor(ctx.session.user.username);
await ctx.render('article/myarticle.tpl', { list: articleList });
}
```
### EditController
我们添加以下内容:
```
async modifyHtm(){
const {ctx, service} = this;
const article = await service.article.getArticleById(ctx.params.id);
await ctx.render('article/modify.tpl',{article:article})
}
async modify(){
const {ctx, service} = this;
const article = ctx.request.body.article;
const nowTime = new Date();
article.update_time = nowTime;
const result = await service.article.modify(article);
if (result) {
ctx.body = {flag:'1',msg:'保存成功',url:'/article/'+article.id+'.htm'}
}else {
ctx.body = {flag:'0',msg:'保存失败'}
}
}
```
### ArticleService
我们添加以下内容:
```
async modify(article = {}){
const res = await this.app.mysql.update('article',article);
return res.affectedRows === 1;
}
async getArticleByAuthor(author){
const sql = "SELECT id,url,title,author,update_time,invisible FROM article WHERE author = ?";
const list =await this.app.mysql.query(sql, [author]);
return list;
}
async getArticleById(id){
const sql = "SELECT id,title,detail,invisible FROM article WHERE id = ?";
const list =await this.app.mysql.query(sql, [id]);
return list[0];
}
```
###搜索文章、用户注销和修改等功能请下载代码包自行学习
##结尾
我是妖云小离,这是我第5次在demo大师上面发表文章,有不正确的地方欢迎大家指出。邮箱:yaoyunxiaoli@163.com