相关文章

基于阿里egg框架搭建博客(1)——开发准备
基于阿里egg框架搭建博客(2)——Hello World
基于阿里egg框架搭建博客(3)——注册与登录
基于阿里egg框架搭建博客(4)——权限控制
基于阿里egg框架搭建博客(5)——置顶导航条
基于阿里egg框架搭建博客(6)——浏览、发表文章
基于阿里egg框架搭建博客(7)——编辑文章

git

https://github.com/ZzzSimon/e...
喜欢就点个赞吧!

正文

编辑文章,首先得把文章原先内容获取到,然后放在编辑页,给用户展现出一个“半成品”的状态,可以重新保存文章。

页面设计

我的文章页面

编辑页面

功能设计

  1. 我的文章页标题前显示是否保密,标题后有编辑按钮
  2. 点击编辑按钮,进入编辑页面可重新编辑文章

前端代码

myarticle.tpl 我的文章页

我们创建/app/view/article/myarticle.tpl页面:

{% extends "parent.tpl" %}

{% block head %}
<!--注意:模板中已添加bootstrap相关head-->
<title>我的文章</title>
{% endblock %}

{% block content %}
<h1>我的文章</h1>
<ul class="article-view view">
    {% for item in list %}
    <li class="item">
        <dl>
            <dt>
                <small style="color: red">{{helper.formatInvisible(item.invisible)}}</small>
                <a href="{{ item.url }}">{{ item.title }}</a>
                <a class="btn btn-link" href='/modify/{{item.id}}.htm'>编辑</a>
            </dt>
            <dd><small>{{item.author}}</small> 最后更新于 {{helper.formatTime(item.update_time)}}  </dd>
            <dd></dd>
        </dl>
    </li>
    {% endfor %}
</ul>
{% endblock %}

此处需要注意1点:

  1. helper.formatInvisiblehelper.formatTime两个方法的作用是格式化后端返回的参数。当然,你也可以在后端代码执行这些逻辑,不过我更倾向于后端代码尽量精简。格式化应当归属于前端范畴。如果说模板的渲染属于后端逻辑,那当我没说= =。
关于helper用法:https://eggjs.org/zh-cn/basic...

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 %}
<title>编辑文章</title>
<link rel="stylesheet" href="/public/editormd/editormd.css">
<script type="text/javascript" src="/public/editormd/editormd.js"></script>
{% endblock %}

{% block content %}
<div class="row">
    <div class="form-group">
        <label for="title">文章标题:</label>
        <input id="title" type="text" class="form-control" value="{{article.title}}">
    </div>
    <div class="checkbox ">
        <label>
            <input id="invisible" type="checkbox" >保密(勾选后将<strong style="color: red">不显示</strong>在文章列表)
        </label>
    </div>
    <div id="detail" style="visibility: hidden">{{article.detail}}</div>
    <div class="form-group pull-right">
        <button id="save" class="btn btn-success ">保存</button>
    </div>
</div>
<div class="row">
    <div id="layout">
        <div id="test-editormd"></div>
    </div>
</div>
{% endblock %}

{% block script %}
<script type="text/javascript">

    $('#invisible').prop('checked','{{article.invisible}}' === '1' ? 'checked':'');
    const markdown = $('#detail').text();
    let testEditor = editormd("test-editormd", {
        width: "100%",
        height: 740,
        path: '/public/editormd/lib/',
        markdown: markdown,
        codeFold: true,
        saveHTMLToTextarea: true,    // 保存 HTML 到 Textarea
        searchReplace: true,
        htmlDecode: "style,script,iframe|on*",            // 开启 HTML 标签解析,为了安全性,默认不开启
        emoji: true,
        taskList: true,
        tocm: true,         // Using [TOCM]
        tex: true,                   // 开启科学公式TeX语言支持,默认关闭
        flowChart: true,             // 开启流程图支持,默认关闭
        sequenceDiagram: true,       // 开启时序/序列图支持,默认关闭,
        imageUpload: true,
        imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
        imageUploadURL: "/edit/uploadPic?_csrf={{ ctx.csrf | safe }}",
        onload: function () {
            console.log('onload', this);
        }
    });

    $('#save').bind('click', function () {
        data = {
            article: {
                id: '{{article.id}}',
                title: $('#title').val(),
                detail: testEditor.getMarkdown(),
                invisible: $('#invisible').prop('checked')  ? 1:0
            }
        };

        $.post('/edit/modify?_csrf={{ ctx.csrf | safe }}', data, function (resp) {
            if (resp.flag === '1') {
                window.location.href = resp.url;
            }else {
                alert(resp)
            }
        })
    })
</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];
    }

结尾

如果看完觉得有用,请给作者一个喜欢吧!谢谢啦!


妖云小离
38 声望1 粉丝

好想当个太空人,这样的话只要我质量够大,你们都得围着我转~~