好久没有写博了,最近趁放假做了一个个人的博客系统。由于没有看什么指导教程,基本上都是自己摸索,所以踩了很多坑,做的时间也很长。终于磕磕碰碰把它给搞出来了,基本有也有个博客的样子,但很多地方都比较粗糙,还需要后续的优化。下面我就来介绍一下这个博客系统。
首页
上面的图片便是博客系统的首页,笔者对前端css,html之类的一直没有系统的学习过,所以直接使用了vue的UI库vuetify,页面最左侧是最普通的侧栏,主题是左右两个部分,左边浏览,右侧最新,最热推荐,和博客标签。具体代码就不做称述,最后会贴上github的地址,这里说一下应该注意的问题。由于vue的核心是面向组件,因此一定要组件的复用,如右侧的最新、最热推荐列表,基本上是除了数据不一样,其它的结构均是相同。所以完全可以用props、emit来达到组件的完全复用。
<template>
<v-card>
<v-card-title>
<v-chip label color="primary" text-color="white">
<v-icon left>{{ iconType }}</v-icon>
{{ listType }}
</v-chip>
</v-card-title>
<v-list :three-line="threeLine">
<template v-for="(item, index) in items">
<v-list-tile @click="toggle(item.id)" :key="index">
<v-list-tile-content>
{{ item.title }}
</v-list-tile-content>
<v-list-tile-action>
<v-list-tile-action-text>{{ index + 1 }}</v-list-tile-action-text>
</v-list-tile-action>
</v-list-tile>
<v-divider v-if="index + 1 < items.length" :key="index+'d'"></v-divider>
</template>
</v-list>
</v-card>
</template>
<script>
export default {
props: {
listType: {
type: String,
default: ''
},
iconType: {
type: String,
default: ''
},
items: {
type: Array,
default: []
},
threeLine: {
type: Boolean,
default: false
}
},
data() {
return {};
},
methods: {
toggle(id) {
// console.log(id);
this.$router.push({ path: `article/${id}` });
}
}
};
</script>
上面的代码便是推荐列表的基本组件,可以看到几乎全是通过props控制数据内容以及标签的样式,在方法上,它也仅有被点击之后跳转的一个toggle函数。因此便可以很好的通过参数传入达到组件的复用。
搜索
<v-menu min-width="500" offset-y>
<v-text-field solo clearable append-icon="search" slot="activator" v-model="query" placeholder="搜索"></v-text-field>
<v-list v-if="suggestions.length > 0">
<v-list-tile v-for="(item,index) in suggestions" :key="index" @click="select(item.id)">
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
这里的搜索框并没有单独的写出来一个组件,而是改造vuetify里面的dropmenu组件,将dropmenu的Button替换成了textfield然后便可以根据输入内容,显示所搜结果。至于数据与后台的交互,我均写在了api.js文件里面。
func GetSearchSuggestions(keyword string) ([]byte, error) {
suggest := elastic.NewCompletionSuggester("mySuggest").
Text(keyword).
Field("suggest").
Fuzziness(2).
Size(3)
res, err := client.Search().
Index("blog").
Suggester(suggest).
Do(ctx)
ErrorPrint(err)
bytes, err := json.MarshalIndent(res, "", " ")
if err == nil {
return bytes, nil
}
return []byte("null"), err
这段代码是suggest获取的后台代码,由于elasticsearch已经在suggest上面做的很好了,所以可以直接根据前段传来的keyword然后请求elasticsearch,至于elasticsearch的使用,由于笔者在这方面也不是很熟悉,不敢过多阐述,想要了解的可以直接去官网查阅。
编辑
我们知道,博客系统的灵魂是编辑页面,所以我简单的通过vue集成了simplemde实现了markdown的编辑功能。
<template>
<div id="simplemde-container">
<textarea ref="md"></textarea>
</div>
</template>
<script>
import '../../commnon/css/simplemde.min.css';
import Simplemde from 'simplemde';
export default {
model: {
prop: 'mdValue',
event: 'input'
},
props: {
mdValue: {
type: String,
default: '## 测试'
}
},
watch: {
mdValue(value) {
if (value === this.simplemde.value()) return;
this.simplemde.value(value);
}
},
name: 'markdown',
data() {
return {
simplemde: null
};
},
mounted() {
this.simplemde = new Simplemde({
element: this.$refs.md,
autoDownloadFontAwesome: true,
autofocus: false,
// toolbar: this.toolbar,
spellChecker: false,
insertTexts: {
link: ['[', ']( )']
},
hideIcons: ['preview', 'side-by-side', 'fullscreen'],
// 'guide', 'heading', 'quote', 'image',
// placeholder: '# 标题',
initialValue: this.mdValue
});
this.simplemde.codemirror.on('change', () => {
this.$emit('input', this.simplemde.value());
});
},
destroyed() {
this.simplemde.toTextArea();
this.simplemde = null;
}
};
</script>
上面的代码便是vue与simplemde集成的基本组件,也是通过emit与props达到高度的可重用性。
管理
一个博客系统也不可缺少管理界面,管理面可通过登录后直接进入管理界面。
后端
后端使用了go语言来搭建,整体上也都是api的请求与elasticsearch的交互,具体的细节请查看源代码。blog好了,介绍完了,祝大家小年快乐。