简介
其实在主界面写好之后,分类和标签页面其实就很简单了,下面主要来介绍一下我踩过的坑。
实现
标签页面
1、因为主界面中的文章卡片可以复用,所以我们单独抽取成组件
2、新建 @/components/ArticleItem.vue
组件
<template>
<el-card>
<div slot="header">
<router-link class="main-text" :to="'/post/' + article.id" v-html="article.title"></router-link>
<div class="article-info">
<el-tag effect="dark" size="mini">原创</el-tag>
浏览量:{{article.views}} 分类:
<router-link
class="link secondary-text"
:to="'/category/'+article.category"
>{{article.category}}</router-link>
</div>
</div>
<div class="tabloid">{{article.tabloid}}</div>
<i class="el-icon-user-solid article-icon">{{article.author}}</i>
<i class="el-icon-date article-icon">{{article.gmtCreate}}</i>
<i class="el-icon-price-tag article-icon">
<router-link
class="tag"
v-for="(tag,index) in article.tags"
:key="index"
v-text="tag"
:to="'/tag/'+tag"
></router-link>
</i>
</el-card>
</template>
<script>
export default {
name: "ArticleItem",
props: ["article"],
};
</script>
<style scoped>
.el-card {
margin-top: 20px;
}
.article-info {
margin-top: 10px;
color: #909399;
font-size: 13px;
}
.article-icon,
.article-icon .tag {
color: #909399;
font-size: 13px;
margin-right: 10px;
text-decoration: none;
}
.article-icon .tag:hover {
color: #409eff;
cursor: pointer;
}
.tabloid {
color: #606266;
font-size: 14px;
margin-bottom: 10px;
}
</style>
代码都是从主页面抄过来的,就不在详述
3、在主界面引入组件
4、编写 Tag.vue 的 js 部分
import request from "@/http/request";
export default {
name: "Tag",
data() {
return {
pageInfo: [],
tags: [],
};
},
components: {
ArticleItem: () => import("@/components/ArticleItem.vue"),
},
methods: {
getArticlesInTagView(page, limit) {
const tag = this.$route.params.name;
if (tag === "all") {
request
.getArticles(page, limit)
.then((res) => {
if (res.code === 0) {
this.pageInfo = res.data;
} else {
this.$notify.error({
title: "提示",
message: res.msg,
});
}
})
.catch((err) => {
console.log(err);
this.$notify.error({
title: "提示",
message: "网络忙,文章获取失败",
});
});
} else {
request
.getArticlesByTag(tag, page, limit)
.then((res) => {
if (res.code === 0) {
this.pageInfo = res.data;
} else {
this.$notify.error({
title: "提示",
message: res.msg,
});
}
})
.catch((err) => {
console.log(err);
this.$notify.error({
title: "提示",
message: "网络忙,文章获取失败",
});
});
}
},
loadData() {
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: "网络忙,标签获取失败",
});
});
this.getArticlesInTagView(1, 5);
},
handleCurrentChange(page) {
this.getArticlesInTagView(page, 5);
},
},
beforeRouteUpdate(to, from, next) {
next();
console.log(to);
console.log(from);
this.loadData();
},
created() {
this.loadData();
},
};
说明:
- 组件创建的时候调用 loadData 函数从后端获取数据,如果路径参数为 all 的话就获取总的文章,否则根据分类获取文章
- beforeRouteUpdate 函数在当前路由改变,但是该组件被复用时调用。举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。注意:这里写在 created 函数中不能实现对应效果,因为created 函数只调用了一次
加了 beforeRouteUpdate 函数之后我的项目报如下错误:
百度了一下,在 @/router/index.js
中加入如下代码即可
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
上面网络请求对应 @/http/request.js
中的下面函数:
getAllTags() {
return instance.get(urls.tags).then(res => res.data);
},
getArticlesByTag(tag, page, limit) {
return instance.get(urls.tag + "/" + tag, {
params: {
page: page,
limit: limit
}
}).then(res => res.data);
},
5、页面布局以及样式
<template>
<el-row :gutter="0">
<el-col :span="14" :offset="5">
<div class="tag-box">
<router-link :to="'/tag/' + tag" v-for="(tag,index) in tags" :key="index">
<el-tag
:class="tag === $route.params.name ? 'tag-selected' : ''"
effect="plain"
size="small"
>{{tag}}</el-tag>
</router-link>
</div>
<article-item v-for="article in pageInfo.records" :key="article.id" :article="article"></article-item>
<el-pagination
background
@current-change="handleCurrentChange"
:current-page.sync="pageInfo.current"
:page-size="pageInfo.size"
layout="prev, pager, next, jumper"
:total="pageInfo.total"
:hide-on-single-page="true"
></el-pagination>
</el-col>
</el-row>
</template>
<script>
// 此处省略......
</script>
<style scoped>
.tag-box {
margin: 10px 0;
}
.tag-box .el-tag {
margin: 0 2px;
}
.tag-box .el-tag:hover {
background-color: #409eff;
color: #ffffff;
cursor: pointer;
}
.tag-selected {
background-color: #409eff;
color: #ffffff;
cursor: pointer;
}
.el-pagination {
margin: 20px 0;
text-align: center;
}
</style>
说明:
- 使用 el-col 实现分栏布局,总共24份,主体部分占14份,向右偏移5份
:class="tag === $route.params.name ? 'tag-selected' : ''"
实现被选中的标签改变样式的效果- 最下方分页效果和首页类似
6、页面效果
分类页面
1、分类页面和标签页面基本类似,这里就直接上代码了
<template>
<el-row :gutter="0">
<el-col :span="14" :offset="5">
<router-link
:to="'/category/' + category.name"
:class="category.name === $route.params.name ? 'category-item category-selected' : '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>
<article-item v-for="article in pageInfo.records" :key="article.id" :article="article"></article-item>
<el-pagination
background
@current-change="handleCurrentChange"
:current-page.sync="pageInfo.current"
:page-size="pageInfo.size"
layout="prev, pager, next, jumper"
:total="pageInfo.total"
:hide-on-single-page="true"
></el-pagination>
</el-col>
</el-row>
</template>
<script>
import request from "@/http/request";
export default {
name: "Category",
data() {
return {
pageInfo: [],
categories: [],
};
},
components: {
ArticleItem: () => import("@/components/ArticleItem.vue"),
},
methods: {
getArticlesInCategoryView(page, limit) {
const category = this.$route.params.name;
if (category === "all") {
request
.getArticles(page, limit)
.then((res) => {
if (res.code === 0) {
this.pageInfo = res.data;
} else {
this.$notify.error({
title: "提示",
message: res.msg,
});
}
})
.catch((err) => {
console.log(err);
this.$notify.error({
title: "提示",
message: "网络忙,文章获取失败",
});
});
} else {
request
.getArticlesByCategory(category, page, limit)
.then((res) => {
if (res.code === 0) {
this.pageInfo = res.data;
} else {
this.$notify.error({
title: "提示",
message: res.msg,
});
}
})
.catch((err) => {
console.log(err);
this.$notify.error({
title: "提示",
message: "网络忙,文章获取失败",
});
});
}
},
loadData() {
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: "网络忙,分类获取失败",
});
});
this.getArticlesInCategoryView(1, 5);
},
handleCurrentChange(page) {
this.getArticlesInCategoryView(page, 5);
},
},
beforeRouteUpdate(to, from, next) {
next();
console.log(to);
console.log(from);
this.loadData();
},
created() {
this.loadData();
},
};
</script>
<style scoped>
.category-item {
display: inline-block;
width: 20%;
text-decoration: none;
font-size: 14px;
color: #606266;
margin-top: 10px;
margin-right: 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-selected {
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;
}
.el-pagination {
margin: 20px 0;
text-align: center;
}
</style>
2、页面效果
参考代码:https://gitee.com/qianyucc/QBlog2/tree/v-7.0