这一个系列的前面几篇,从安装 mysql 到 Node 操作 mysql 再到 将 Node 项目按照 MVC 架构拆分组织,这一篇实现一个简单的简书获取文章列表,添加文章,更新文章,删除文章的操作,来巩固一下前面学习的知识。
首先还在之前的 koa-test 下新建一个md_to_html 的文件夹,前端不使用任何框架,直接原生操作,因为重点不是在前端,而是在后端接口实现上。实现的效果如下:

可以新建文章,获取文章的列表, 更新编辑文章,删除文章,每一次操作都会重新请求最新的文章列表。
前端部分
先看前端部分,主要分为 html , css,js,这一块都是直接写,html,css 没什么好说的,贴一下 js 的代码吧,js 主要都在手动操作 dom 上,其中有一个点就是更新文章的时候,做了防抖处理,在300毫秒之后再去请求更新接口,不至于只要输入发生变化就频繁的请求接口。
// static/js/index.js
;(function(){
const { debounce } = MD2HTML_Util
const {
addService,
getContentService,
getListService,
deleteService,
updateService
} = MD2HTML_Service
const new_article = document.getElementById('new_article')
const articleList = document.getElementById('article-list')
const add_title = document.getElementById('add_title')
const editor_origin = document.getElementById('editor-origin')
const html_title = document.getElementById('html-title')
const html_content = document.getElementById('html-content')
let ID = null;
let global_index = 0
function addController (params, cb){
let id = null, content = null, title = null
addService(params)
.then((res) => {
return new Promise((resolve, reject) => {
id = res.data.id
title = res.data.title
getContentService(id)
.then((resp) => {
content = resp.data.content
resolve()
})
})
})
.then(() => {
if(cb) cb({id, title, content})
})
}
function getArticleList(){
getListService()
.then((resp) => {
if(resp.code == 0){
//resp.data.reverse();
let fragment = document.createDocumentFragment()
resp.data.forEach((item, index) => {
let li = document.createElement('li')
li.setAttribute('data-index', index)
li.setAttribute('data-id', item.id)
li.className = 'li-title';
li.textContent = item.title
let span = document.createElement('span')
span.setAttribute('data-id', item.id)
span.className = 'delete-article'
span.textContent = '删除'
li.appendChild(span)
fragment.appendChild(li)
})
if(articleList.children.length > 0){
articleList.innerHTML = ''
}
articleList.appendChild(fragment)
const li = articleList.querySelectorAll('.li-title')
if(li.length > 0){
if(global_index != 0){
ID = resp.data[global_index].id
title = resp.data[global_index].title
content = resp.data[global_index].content
li[global_index].className = 'li-title active'
} else{
ID = resp.data[0].id
title = resp.data[0].title
content = resp.data[0].content
li[0].className = 'li-title active'
}
}
add_title.value = html_title.innerHTML = title
editor_origin.value = content
html_content.innerHTML = renderHtml(content)
} else {
console.log(resp.message)
}
})
}
function updateArticle(params){
updateService(params)
.then(res => {
const data = res.data
if(res.code === 0){
html_title.innerHTML = data.title
html_content.innerHTML = renderHtml(data.content)
add_title.value = data.title
editor_origin.value = data.content
getArticleList()
}
})
}
getArticleList();
new_article.onclick = function(){
addController({title: '2019-11-14', author: 'hcj'}, (article) => {
add_title.value = article.title
editor_origin.value = article.content
})
getArticleList()
}
articleList.onclick = function(e){
const target = e.target
const li = articleList.querySelectorAll('.li-title')
if(target.className.indexOf('li-title') > -1){
const index = target.getAttribute('data-index')
global_index = index
const id = target.getAttribute('data-id')
ID = id
li.forEach((item) => {
item.className = 'li-title'
})
li[index].className = 'li-title active'
getContentService(id)
.then((resp) => {
add_title.value = resp.data.title
editor_origin.value = resp.data.content
html_title.innerHTML = resp.data.title
html_content.innerHTML = renderHtml(resp.data.content)
})
}
if(target.className == 'delete-article'){
//删除接口
const id = target.getAttribute('data-id')
deleteService(id)
.then((res) => {
if(res.code === 0){
getArticleList();
} else {
console.log(res.message)
}
})
}
}
add_title.onkeyup = editor_origin.onkeyup = debounce(() => {
const params = {
id: ID,
title: add_title.value,
content: editor_origin.value,
author: 'hcj'
}
updateArticle(params)
}, 1000)
function renderHtml(text){
let htmlStr = MdtoHtml(text)
return htmlStr;
}
})();
后端接口实现
依然跟之前的差不多,大概看看吧。
// server/server.js
const Koa = require('koa')
const static = require('koa-static')
const Router = require('koa-router')
const koaBody = require('koa-body')
const { join } = require('path')
const { query } = require('./db/db')
const { addSql } = require('./db/sql/article_sql')
const staticPath = '../static'
const app = new Koa()
const router = new Router()
app.use(koaBody());
app.use(static(join(__dirname, staticPath)))
app.use(router.routes()).use(router.allowedMethods())
router.get('/articleList', async (ctx, next) => {
let list = await query('SELECT * FROM article;')
let data = [];
list.forEach(({ id, title, author, content, createTime }) => {
data.push({
id,
title,
author,
content,
createTime
})
})
ctx.body = {
code: 0,
data,
message: 'get list success'
}
})
router.post('/add', async (ctx, next) => {
const params = ctx.request.body
let result = await query(addSql, params)
ctx.body = {
code: 0,
data: {
id: result.insertId,
title: params.title,
},
message: 'add success'
}
})
router.get('/getContent/:id', async (ctx, next) => {
let result = await query('SELECT * FROM article WHERE id = ?;', ctx.params.id)
ctx.body = {
code: 0,
data: {
title: result[0].title,
content: result[0].content
},
message: 'get content success'
}
})
router.put('/update/:id', async (ctx, next) => {
const postData = ctx.request.body
await query('UPDATE article SET title = ?, content = ?, author = ? WHERE id = ?;', [postData.title, postData.content, postData.author, postData.id])
const result = await query('SELECT * FROM article WHERE id = ?;', ctx.params.id)
ctx.body = {
code: 0,
data: result[0],
message: 'update success'
}
})
router.post('/delete', async (ctx, next) => {
const postData = ctx.request.body;
await query('DELETE FROM article WHERE id = ?;', postData.id)
ctx.body = {
code: 0,
data:{},
message: 'delete success'
}
})
app.listen(3000)
console.log('listenning at port 3000')
其实这一篇文章跟其他的几篇没什么太大的区别,我写这个小项目是为了写一个 markdown 的转译器,将左边的 markdown 语法实时转译为右边的 html 显示出来。本来想随便写个页面,但是由于强迫症,还是想看着能好看点,就多写了很多样式,js 操作之类的代码,兜了一大圈,那就当做是巩固知识吧,毕竟 12 月快过完了,还没出一篇文章,心慌慌,就当是凑篇幅了,(捂脸)。
github 地址:https://github.com/mxcz213/koa-test
分支切到md_to_html
就可以看到了。
网友评论