启动本地Mongo以及Egg服务,随后启动博客后台,编辑文章,将文章数据保存在本地Mongo数据库。将本地Mongo数据导出为JSON,前台页面用静态JSON渲染,经过webpack将前台工程打包成静态页,全部静态资源托管于github page。经过github page提供的映射域名便可访问静态页index.html。css
该静态博客搭建适合有必定基础,须要项目练手的初级前端开发工程师。博客搭建省时省力,堪称居家必备良品。一方面有利用提高自身综合实力,另外一方面不用为域名和服务器的到期而堪忧。当文章质量获得保证时,有利于提升github知名度。html
UI设计前端
因为博主本人对设计领域着实没有建树,因此该博客的UI设计借鉴了一位小姐姐的博客UInode
路由设计react
搭建工程目录webpack
├── config
│ ├── config.js
│ └── proxyConfig.js
├── package.json
├── src
│ ├── assets
│ ├── common
│ ├── components
│ ├── global.less
│ ├── layouts
│ ├── pages
│ ├── plugins
│ │ └── rematchPlugin
│ │ ├── createPlugin.d.ts
│ │ ├── createPlugin.js
│ │ ├── index.js
│ │ ├── runtime.ts
│ │ ├── template
│ │ │ ├── RematchContainer.tsx
│ │ │ └── Store.ts
│ │ └── ulits.js
│ ├── services
│ ├── store.ts
│ ├── types
│ └── utils
├── tsconfig.json
├── tslint.json
├── typings.d.ts
复制代码
响应式设计git
博客响应式设计主要采用了Antd的栅格化系统以及enquire-js来判断浏览设备窗口大小github
封装工具类:web
/**
* @name 判断浏览设备
*/
export function distingIsMobile<T>(): boolean {
let isMobile = false;
enquireScreen(value => {
isMobile = value;
});
return isMobile;
}
复制代码
技术难点mongodb
我首先采用了react-markdown来渲染markdown语法。可是该组件存在必定的问题:
code代码块语法高亮没法实现,网上的一些解决办法并不生效。 因而我放弃了使用这个组件。转向了markdown-it。同时结合markdown-it-highlightjs实现code语法高亮,以此作了一个简单的封装,实现本身的markdown组件。
import React, { Component, Fragment } from 'react';
import { Basic } from 'src/types';
const marked = require('markdown-it')().use(require('markdown-it-highlightjs'));
interface Props extends Basic.BaseProps {
source: string;
}
export default class ReactMarkdown extends Component<Props> {
renderMarkdown = () => {
const source = this.props.source;
return <div dangerouslySetInnerHTML={{ __html: marked.render(source) }} />;
};
render() {
return <Fragment>{this.renderMarkdown()}</Fragment>;
}
}
复制代码
一切搞定以后,发现code标签内的代码已经成功分割为独立的标签,可是css并未生效,是由于还未定义高亮的css样式,因而我找到highlight.js官网,选了一个中意的高亮样式,而后在github中找到这个样式的css文件,copy到项目中,搞定!
blockquote {
padding: 0 1rem;
margin-left: 0;
color: #819198;
border-left: .3rem solid #dce6f0;
}
复制代码
模块设计
最终效果
代理配置
const devPath = 'http://127.0.0.1:7001'; // 代理地址指向本地egg服务运行地址
export default {
'/api/': {
target: devPath,
changeOrigin: false
}
};
复制代码
技术难点
MarkDown编辑器选型
博主最终采用SimpleMDE。
效果图:
实例化:
componentDidMount() {
this.renderContEditorNode(); // 实例化内容编辑器
this.renderSumEditorNode(); // 实例化摘要编辑器
}
renderContEditorNode() {
this.contEditNode = new SimpleMDE({
element: document.getElementById('contEditor').childElementCount,
...simpleMdConfig
});
}
renderSumEditorNode() {
this.sumEditNode = new SimpleMDE({
element: document.getElementById('sumEditor').childElementCount,
...simpleMdConfig
});
}
复制代码
编辑器simpleMdConfig配置:
/**
* @name SimpleMDE配置
*/
export const simpleMdConfig = {
autofocus: true,
autosave: true,
shortcuts: {
drawTable: 'Cmd-Alt-T'
},
showIcons: ['code', 'table'],
tabSize: 4,
placeholder: '在这里编辑',
toolbar: [
'bold',
'italic',
'strikethrough',
'heading',
'code',
'quote',
'unordered-list',
'ordered-list',
'clean-block',
'link',
'image',
'table',
'horizontal-rule',
'preview',
'side-by-side',
'fullscreen',
'guide'
],
previewRender(plainText) {
return marked(plainText, {
renderer: new marked.Renderer(),
gfm: true,
pedantic: false,
sanitize: false,
tables: true,
breaks: true,
smartLists: true,
smartypants: true,
highlight(code) {
return highlight.highlightAuto(code).value; // 采用highlight.js实现代码块语法高亮
}
});
}
};
复制代码
碰见的问题:
{
key: 'summary',
label: '摘要 - 内容',
node: (
<textarea
style={{ maxHeight: '300px', overflow: 'auto' }}
id="sumEditor"
/>
)
},
{
key: 'content',
node: (
<textarea
id="contEditor"
style={{ maxHeight: '300px', overflow: 'auto' }}
/>
)
},
复制代码
因为我采用了本身封装的表单组件,组件内部存在必定的异步渲染,所以在页面渲染结束时,没法找到实例化的textarea元素,所以报错。
解决办法:
在render函数内写入两个隐藏的textarea元素,保障组件实例化后可以找到对应的dom元素,从而成功实例化编辑器。
<textarea id="contEditor" style={{ display: 'none', maxHeight: '300px', overflow: 'auto' }} />
<textarea id="sumEditor" style={{ display: 'none', maxHeight: '300px', overflow: 'auto' }} />
复制代码
经过官方脚手架叫快速生成
$ npm i egg-init -g
$ egg-init egg-example --type=simple
$ cd egg-example
$ npm i
复制代码
修改配置
'use strict';
module.exports = appInfo => {
const config = (exports = {});
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1544961945990_6105';
// add your config here
config.middleware = [];
/**
* @name mongo配置,经过egg-mongoose链接mongo
*/
config.mongoose = {
url: 'mongodb://127.0.0.1:27017/MingShined',
options: {
useMongoClient: true,
autoReconnect: true,
reconnectTries: Number.MAX_VALUE,
bufferMaxEntries: 0
}
};
/**
* @name 关闭csrf
*/
config.security = {
csrf: {
enable: false
}
};
return config;
};
复制代码
启动项目
$ npm run dev
$ open localhost:7001
复制代码
数据库设计
restfulApi风格的路由设计
'use strict';
module.exports = app => {
const { router, controller } = app;
/**
* @name 新增文章
*/
router.post('/api/article', controller.article.article.createArticle);
/**
* @name 导出文章
*/
router.get(
'/api/article/download',
controller.article.article.downloadArticle
);
/**
* @name 获取文章列表
*/
router.get('/api/article', controller.article.article.queryArticleList);
/**
* @name 编辑文章
*/
router.put('/api/article', controller.article.article.updateArticle);
/**
* @name 获取文章详情
*/
router.get('/api/article/:id', controller.article.article.findArticle);
/**
* @name 获取文章详情
*/
router.delete('/api/article/:id', controller.article.article.deleteArticle);
/**
* @name 获取关于我
*/
router.get('/api/about', controller.article.article.getAbout);
/**
* @name 保存关于我
*/
router.post('/api/about', controller.article.article.createAbout);
/**
* @name 下载关于我
*/
router.get('/api/about/download', controller.article.article.downloadAbout);
};
复制代码
技术难点
/**
* @name 下载文章
*/
async downloadArticle() {
const json = await this.service.article.queryArticleList();
this.ctx.attachment('article.json');
this.ctx.set('Content-Type', 'application/json');
this.ctx.body = JSON.stringify(json);
}
复制代码
总的来讲,纯手撸一个静态博客仍是挺有成就感。整个过程遇到种种问题,在这个过程当中,不断总结进步,提高较大。搭建成功后,也为本身开拓了一个属于本身的平台,通用的md语法也能够同步到知乎,掘金等社区。对博主以及博主的文章有什么意见建议,欢迎联系博主。