Gin blog I
本节将实现前端页面的如下功能:
- 文章列表
- 文章添加, 修改和删除
- 文章内容展示
1. 初始化
1.1 采用模板
以 vue-admin-template 为模板创建仓库 gin-blog , clone 到本地
gh repo clone dreamjz/gin-blog
安装依赖
yarn install --registry=https://registry.npm.taobao.org
启动
yarn run dev
项目正常启动并能进入 dashboard
1.2 获取完全项目
将 vue-element-admin 项目 clone 到本地
gh repo clone PanJiaChen/vue-element-admin
安装依赖
yarn install --registry=https://registry.npm.taobao.org
启动
yarn run dev
项目正常启动并能进入 dashboard
1.3 添加文章编辑页和文章列表页
将 vue-element-admin 中的文章页相关的组件拷贝至 gin-blog
src/views/router/index.js
添加路由
{
path: '/article',
component: Layout,
redirect: '/article/list',
name: 'Article',
meta: {
title: 'Article',
icon: 'el-icon-s-help'
},
children: [
{
path: 'create',
component: () => import('@/views/article/create'),
name: 'CreateArticle',
meta: { title: 'Create Article', icon: 'edit' }
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/article/edit'),
name: 'EditArticle',
meta: {
title: 'Edit Article',
noCache: true,
activeMenu: '/example/list'
},
hidden: true
},
{
path: 'list',
component: () => import('@/views/article/list'),
name: 'ArticleList',
meta: { title: 'Article List', icon: 'list' }
}
]
},
更新 src/store/index.js
, 实现自动导入 modules
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
getters
})
export default store
配置src/mock/index.js
mock server
const article = require('./article')
const mocks = [...user, ...article]
启动项目即可看到文章编辑页和文章列表页
2. 添加文章浏览页
经过上述步骤,成功添加了文章列表和编辑页面,但是作为一个 blog 应用还需要一个浏览文章内容的页面
我的个人网站使用 vuepress 进行构建,其使用了 markdown-it 进行 markdown 文件的渲染,下面也使用markdown-it 来渲染文章内容
MDContent
组件
2.1 创建 yarn add markdown-it --save
创建 src/components/Markdown/index.vue
<template>
<component :is="mdHtml" class="md-content" />
</template>
<script>
import MarkdownIt from 'markdown-it'
export default {
name: 'Markdown',
props: {
content: {
type: String,
default: ''
}
},
data: () => ({
md: null
}),
computed: {
mdHtml: function() {
const res = this.md.render(this.content)
return {
template: '<div>' + res + '</div>'
}
}
},
created() {
this.md = new MarkdownIt()
}
}
</script>
这里使用了动态插件,方便后续的扩展,同时需要配置 vue 的动态渲染
修改 vue.config.js
module.exports = {
runtimeCompiler: true
}
2.2 文章内容页
创建src/views/article/content.vue
<template>
<div>
<Markdown :content="content" />
</div>
</template>
<script>
import Markdown from '@/components/Markdown'
export default {
name: 'ArticleContent',
comments: {
Markdown
},
data: () => ({
content: ''
}),
created() {
this.content = `# Test \n ## 1. H1`
}
}
</script>
src/router/index.js
添加为 article 的子路由
{
path: 'content',
component: () => import('@/views/article/content'),
name: 'ArticleContent',
meta: { title: 'Article Content', icon: 'content' },
hidden: false
},
启动项目,可以看到新增菜单Article Content
并且渲染测试数据
Test
1. H1
2.3 从文章列表进入
上述步骤成功创建了文章内容页并渲染如测试内容,下面将实现从文章列表点击标题进入其内容页面的功能
修改路由,使其可以获取文章 ID并隐藏其菜单栏
// src/router/index.js
{
path: 'content/:id(\\d+)',
component: () => import('@/views/article/content'),
name: 'ArticleContent',
meta: { title: 'Article Content', icon: 'content' },
hidden: true
},
修改src/views/article/content.vue
,使其在 created 时通过fetchArticle
API 获取文章内容
<template>
<div>
<MDContent :content="content" />
</div>
</template>
<script>
import MDContent from '@/components/MDContent'
import { fetchArticle } from '@/api/article'
const defaultForm = {
status: 'draft',
title: '', // 文章题目
content: '', // 文章内容
content_short: '', // 文章摘要
source_uri: '', // 文章外链
image_uri: '', // 文章图片
display_time: undefined, // 前台展示时间
id: undefined,
platforms: ['a-platform'],
comment_disabled: false,
importance: 0
}
export default {
name: 'ArticleContent',
components: {
MDContent
},
data() {
return {
artileForm: Object.assign({}, defaultForm),
content: ''
}
},
created() {
const id = this.$router.params && this.$router.params.id
this.fetchData(id)
},
methods: {
fetchData(id) {
fetchArticle(id)
.then((response) => {
this.artileForm = response.data
this.content = this.artileForm.content
})
.catch((err) => {
console.log(err)
})
}
}
}
</script>
修改src/views/article/list.vue
, 实现点击标题跳转至内容页
<el-table-column min-width="300px" label="Title">
<template slot-scope="{ row }">
<router-link :to="'/article/content/' + row.id" class="link-type">
<span>{{ row.title }}</span>
</router-link>
</template>
</el-table-column>
启动应用,从文章列表进入内容页,发现文章内容中的 html 没有被解析而是直接以文本形式渲染
<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>
因为 markdown-it 的默认选项中 html
为 false , 修改 MDContent.vue
中 markdown-it
的配置
created() {
this.md = new MarkdownIt({
html: true
})
}
再次启动应用,发现内容被正常渲染并且图片也正显示了
3. 添加删除按钮
回到文章列表页,可以看到只有编辑按钮,下面就在其旁边添加一个删除按钮
修改 src/views/article/list.vue
,在编辑按钮所在单元格添加删除按钮
<el-table-column align="center" label="Actions" width="230">
<template slot-scope="scope">
<router-link :to="'/article/edit/' + scope.row.id">
<el-button class="edit-btn" type="primary" size="small" icon="el-icon-edit">
Edit
</el-button>
</router-link>
<el-button class="del-btn" type="primary" size="small" icon="el-icon-delete" @click="deleteArticle($index)">
Delete
</el-button>
</template>
</el-table-column>
在 methods 中添加删除函数 deleteArticle
deleteArticle(index) {
this.list.splice(index, 1)
}
设置样式
.el-button {
margin-right: 10px;
}
.edit-btn, .del-btn {
width: 85px;
}
这样前端的部分就完成了,接下来完成服务端的实现
Reference
- vue-element-admin official docs
- #316 vue-element-admin github issue
- vue config vue cli docs
- Vue单页面应用中的Markdown渲染 youxam
- markdown-it official docs