Vue博客搭建(9)创作中心

515 阅读2分钟

在之前的几篇文章中,我们做完了注册与登录,这次我们要真的开始做一个创作中心了,也就是写文章。

一个博客需要什么

我们现在前端中创建一个classes文件夹,放上我们需要的所有类。然后在其中创建一个article.js文件,来存放我们的文章类。一个文章类大致需要以下属性:

  • 文章标题,一个字符串
  • 文章作者,一个字符串
  • 文章的唯一id,一个字符串,目前计划用户id+时间戳进行哈希
  • 文章的内容,一个字符串
  • 创建时间,使用JavaScript的Date类即可
  • 点赞数,一个number类型
  • .....

这是我们目前实现一个文章的最基础功能。后续还会继续添加。根据这个我们可以迅速写好一个class。构造函数中只需要传入标题、id和内容,其余的属性可以在构造函数中直接创建。

constructor(title, author, content){
        this.title = title;
        this.author = author;
        this.createTime = Date.now();
        // id使用MD5-16进行加密,这样可以生成一段16位的短id
        this.id = MD5(`${author}${this.createTime}`).toString().slice(0,16);
        this.content = content;
        // 刚创建的文章怎么可能会有赞呢
        this.likes = 0;
    }

我们只实现了构造函数,接下来需要实现其他的功能,包括更新目前的文章信息到服务器、增加文章点赞数量,修改文章信息等。

updateTitle(newTitle){
        if(this.title !==newTitle){
            this.title = newTitle;
            // updateToServer
        }
        
    }
    updateContent(newContent){
        // 因为content太长,在这里不做判断。
        this.content = newContent;
        // updateToServer
    }
    likesUp(){
        this.likes++;
        // updateToServer
    }
    likesDown(){
        this.likes--;
        // updateToServer
    }

在写updateToServer函数之前,我们要先写好后端对应的接口。先通过内部的/createDatabase接口来创建对应的数据库。

app.get('/createDatabase',(req, res)=>{
    connection.query(`create table articles
                    (
                        title varchar(50),
                        author varchar(20),
                        id varchar(16),
                        content text,
                        createTime varchar(20),
                        likes int(8)
                    )`,
    (err,result)=>{
        console.log(err);
        res.send('ok');
    });
})

数据库创建完毕后,就可以编写文章上传的接口了,用的也是post指令。文章id使用的是时间戳+用户名后md5,这样可以得到一个16位的id。

app.post('/addArticle',(req, res)=>{
    const title = req.body.title;
    const author = req.body.author;
    const createTime = req.body.createTime;
    const id = req.body.id;
    const content = req.body.content;
    const likes = req.body.likes;
    const addSql = `insert into articles (title, author, id, content, createTime, likes) values(?,?,?,?,?,?)`;
    const dataArray = [title,author,id, content, createTime, likes]
    connection.query(addSql, dataArray, (err)=>{
        if(err){
            res.status(400).send(`${err}`);
        }else{
            res.send('新建文章成功!');
        }
    })
})

试着用apifox发送一个请求,如果成功的话就说明我们的代码没有问题。

前端页面的编写

我们在pages文件夹中创建一个articleEditor.vue组件,这就是我们的文章编辑器了。组件中大致包含这几要素:两个输入框,一个输入标题一个输入正文。一个博客预览界面,和一个提交按钮。先把页面主干写好并进行基本的路由添加。

<script setup>
import {ref} from 'vue'
import { Article } from '../classes/article';
import { useUserAccountStore } from '../stores/userAccount';

const userAccountStore = useUserAccountStore();

const articleInEditing = ref(new Article('', userAccountStore.username,''));

</script>

<template>
    <input id="titleInput"/>
    <textarea id="contentInput"></textarea>
    <button>发布</button>
</template>

剩下的工作就好办了,给输入框绑定好响应式的属性,然后写好上传到服务器的函数即可。不过这里又出现了一个问题:我们解决了markdown的输入,又该如何解决markdown的渲染呢?自己手写一个当然好,但是这个不是我们博客的重点。因此我们使用bytemd包来进行markdown的输入和渲染,这是一个很现代化的前端包,对Vue和React等框架还有自己的优化。我们直接输入npm install @bytemd/vue-next,然后对前端代码进行一下改造即可。为了防止我们的渲染太难看,我们把所有的css全都删掉(之后会从头开始重新写css)。

<script setup>
import {ref} from 'vue'
import { Article } from '../classes/article';
import { useUserAccountStore } from '../stores/userAccount';
import { Editor} from '@bytemd/vue-next';
import gfm from '@bytemd/plugin-gfm'

import 'bytemd/dist/index.css'

const userAccountStore = useUserAccountStore();
const articleInEditing = ref(new Article('', userAccountStore.username,''));
// 插件,让其支持GFM语法
const plugins =[gfm(),];

function updateRendering(value){
    articleInEditing.value.content = value;
}

</script>

<template>
    <input id="titleInput" v-model="articleInEditing.title"/>
    <!-- 由于没有支持v-model, 所以需要手动实现v-model-->
    <Editor :value = "articleInEditing.content" 
    :plugins="plugins" @change="updateRendering" locate="zh"/>
    <button>发布</button>
</template>

<style scoped>

</style>

不过在上传到服务器的时候,我们还需要考虑一个很严重的问题:我们传数据使用的是JSON,而JSON的格式决定了它需要很多的双引号,也就是说我们需要把单双引号等具有实际功能的字符妥善处理,也就是JSON转义。这里比较简单,直接把所有的双引号全部用转义字符替换即可。

function addArticle(){
    articleInEditing.value.content = articleInEditing.value.content.replaceAll('"','\"');
    axios.post('/server/addArticle',articleInEditing.value)
    .then((response)=>{
        alert(response.data);
    })
    .catch((err)=>{
        alert(`发布文章失败,${err.response.data}`);
    })
}

测试一下,发现可以上传了。