简介
博客信息部分主要放在文章列表的右边,主要包含三个部分:1、个人信息,2、分类列表,3、标签列表
代码实现
因为博客信息在多个组件中用得到,所以可以将其存入 vuex 中, vuex 文档:https://vuex.vuejs.org/zh/
先在 @/http/urls.js
中新增url地址
export default {
baseUrl: "/api/v1",
article: "/article",
articles: "/articles",
tags: "/tags",
tag: "/tag",
categories: "/categories",
category: "/category",
info: "/info"
}
在 @/http/request.js
中封装请求方法
getAllTags() {
return instance.get(urls.tags).then(res => res.data);
},
getAllCategories() {
return instance.get(urls.categories).then(res => res.data);
},
getBlogInfo() {
return instance.get(urls.info).then(res => res.data);
}
在 store 中封装请求博客信息的方法
import Vue from 'vue';
import Vuex from 'vuex';
import request from '@/http/request';
import { Notification } from 'element-ui';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
token: window.sessionStorage.getItem("token"),
userInfo: null,
blogInfo: null
},
mutations: {
setToken(state, token) {
state.token = token;
window.sessionStorage.setItem("token", token);
},
removeToken(state) {
state.token = "";
state.userInfo = null;
window.sessionStorage.removeItem("token");
},
setUserInfo(state, userInfo) {
state.userInfo = userInfo;
},
setBlogInfo(state, blogInfo) {
state.blogInfo = blogInfo;
},
},
actions: {
getBlogInfo({ commit }) {
request.getBlogInfo().then(res => {
if (res.code === 0) {
commit('setBlogInfo', res.data);
} else {
Notification.error({
title: '提示',
message: res.msg
});
}
}).catch(err => {
console.log(err);
Notification.error({
title: '提示',
message: "服务器忙,获取博客信息失败"
});
})
}
}
});
export default store;
说明:
- 这里单独导入 Notification 来实现消息提示的功能
- vuex 中 Action 类似于 mutation,但是 Action 可以包含任意异步操作。
在 Vue 实例创建的时候调用 getBlogInfo函数
import Vue from 'vue'
import App from './App.vue'
import store from "@/store/index"
import router from "@/router/index"
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import 'github-markdown-css/github-markdown.css';
import 'highlight.js/styles/github.css'
Vue.config.productionTip = false
Vue.use(ElementUI);
import { VueShowdown } from 'vue-showdown'
Vue.component('VueShowdown', VueShowdown)
new Vue({
render: h => h(App),
store,
router,
created: initBlog
}).$mount('#app')
function initBlog() {
store.dispatch('getBlogInfo');
}
然后我们就可以修改 Home.vue 了,改成从 vuex 中获取数据
<template>
<div>
<el-carousel indicator-position="none" height="400px" arrow="nerver" :interval="5000">
<el-carousel-item v-for="item in blogInfo.covers" :key="item">
<div class="item-box">
<img :src="item" class="carimg" />
<div class="desc-box">
<h1>{{ blogInfo.title }}</h1>
<p>{{ blogInfo.desc }}</p>
</div>
</div>
</el-carousel-item>
</el-carousel>
<el-row :gutter="20">
<!-- ......此处省略 -->
</el-row>
</div>
</template>
<script>
import request from "@/http/request";
import { mapState } from "vuex";
export default {
name: "Home",
data() {
return {
pageInfo: {}
};
},
computed: mapState(["blogInfo"]),
// ......此处省略
};
</script>
<style scoped>
// ......此处省略
</style>
博客信息组件的封装
新建 @/components/BlogInfo.vue
组件
HTML部分
<template>
<el-card>
<el-avatar :size="96" :src="blogInfo.avatar" fit="cover"></el-avatar>
<div class="nickname">{{blogInfo.nickname}}</div>
<div class="info-box">
<div class="text-center">
<div class="info-count">{{blogInfo.articleCount}}</div>
<div class="info-desc">文章数</div>
</div>
<div class="text-center">
<div class="info-count">{{blogInfo.totalViews}}</div>
<div class="info-desc">浏览量</div>
</div>
</div>
<el-divider></el-divider>
<i class="el-icon-menu">文章分类</i>
<router-link
:to="'/category/' + category.name"
class="category-item"
v-for="(category,index) in categories"
:key="index"
>
{{category.name}}
<el-tag type="success" size="small" effect="dark">{{category.count}}</el-tag>
</router-link>
<el-divider></el-divider>
<i class="el-icon-price-tag">文章标签</i>
<div class="tag-box">
<router-link :to="'/tag/' + tag" v-for="(tag,index) in tags" :key="index">
<el-tag effect="plain" size="small">{{tag}}</el-tag>
</router-link>
</div>
</el-card>
</template>
说明:
- 分为个人信息、文章标签、文章分类三个面板
- 每个面板之间使用 el-divider 分隔,此组件为ElementUI的分割线组件
- 标签和分类分别使用 router-link 组件包裹,点击可跳转到对应路由
js 部分:
import request from "@/http/request";
import { mapState } from "vuex";
export default {
name: "BlogInfo",
data() {
return {
categories: [],
tags: []
};
},
computed: mapState(["blogInfo"]),
created() {
request
.getAllTags()
.then(res => {
if (res.code === 0) {
this.tags = res.data;
} else {
this.$notify.error({
title: "提示",
message: res.msg
});
}
})
.catch(err => {
console.log(err);
this.$notify.error({
title: "提示",
message: "网络忙,标签获取失败"
});
});
request
.getAllCategories()
.then(res => {
if (res.code === 0) {
this.categories = res.data;
} else {
this.$notify.error({
title: "提示",
message: res.msg
});
}
})
.catch(err => {
console.log(err);
this.$notify.error({
title: "提示",
message: "网络忙,文章分类获取失败"
});
});
}
};
说明:
- 在 created 方法中获取分类和标签
- 从 vuex 中取博客信息
css部分:
.el-avatar {
display: block;
margin: 0 auto;
}
.nickname {
margin-top: 5px;
color: #303133;
font-size: 16px;
text-align: center;
}
.info-box {
margin-top: 10px;
display: flex;
justify-content: space-around;
align-items: center;
}
.info-count {
color: #303133;
font-weight: bold;
font-size: 20px;
}
.info-desc {
color: #909399;
font-size: 12px;
}
.category-item {
display: block;
text-decoration: none;
font-size: 14px;
color: #606266;
margin-top: 10px;
padding: 8px;
transition: all 0.5s;
border-radius: 5px;
border: 1px solid #ebeef5;
}
.category-item:hover {
box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 8px 0px;
cursor: pointer;
transform: scale(1.03);
color: #303133;
}
.category-item .el-tag {
float: right;
}
.tag-box {
margin-top: 10px;
}
.tag-box .el-tag {
margin: 0 2px;
}
.tag-box .el-tag:hover {
background-color: #409eff;
color: #ffffff;
cursor: pointer;
}
说明:
- 基本都是一些常见 CSS 属性,主要说一下
transform: scale(1.03);
为方法效果,scale() 的参数为放大倍数。这里的效果是鼠标移动到指定分类的时候,该分类有放大效果 - 另外使用到了 flex 布局,详情可参考:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
然后在主界面博客信息的地方引入该组件就行了。
页面效果:
参考代码:https://gitee.com/qianyucc/QBlog2/tree/v-6.0