跟帖功能是在帖子详情页中,所以我们只需要修改帖子详情页即可,在上个实验的基础上去修改。打开文件site/pages/topic/_id.vue并修改,下面我们先将修改后的完整代码贴出来,再对代码做一个讲解。完整代码如下:
<template>
<section>
<my-nav />
<section class="section">
<div class="container">
<article>
<div class="title">
{{ topic.title }}
<span class="meta"
>By {{topic.user.nickname}} @ {{topic.createTime}}</span
>
</div>
<pre class="content">{{ topic.content }}</pre>
</article>
<hr />
<div>
<div>
<div class="field">
<div class="control">
<textarea
v-model="commentContent"
class="textarea has-fixed-size"
rows="3"
placeholder="请输入评论内容"
></textarea>
</div>
</div>
<nav class="field">
<div class="control">
<button class="button is-link" @click="createComment">
发表
</button>
</div>
</nav>
</div>
<ul class="comments">
<li
class="comment"
v-for="comment in comments"
:key="comment.id"
:id="'comment-' + comment.id"
>
<div class="comment-left">
<img
class="avatar"
src="https://i.loli.net/2019/10/11/Emlz8DiAd6ZoG7U.png"
/>
</div>
<div class="comment-right">
<div class="comment-content">
{{ comment.content }}
</div>
<div class="comment-meta">
By {{comment.user.nickname}} @ {{comment.createTime}}
</div>
</div>
</li>
</ul>
<nav class="pagination" role="navigation" aria-label="pagination">
<a
class="pagination-previous"
:href="page > 1 ? '/topic/' + topic.id + '?page=' + (page - 1) : 'javascript:void(0)'"
>上一页</a
>
<a
class="pagination-next"
:href="page < maxPage ? '/topic/' + topic.id + '?page=' + (page + 1) : 'javascript:void(0)'"
>下一页</a
>
</nav>
</div>
</div>
</section>
<my-footer />
</section>
</template>
<script>
import MyNav from '~/components/MyNav';
import MyFooter from '~/components/MyFooter';
export default {
components: {
MyNav,
MyFooter,
},
data() {
return {
commentContent: '',
page: 1, // 当前页码
maxPage: 0, // 最大页码
};
},
async asyncData({ params, query, $axios }) {
const topicId = params.id; // 从动态路由参数中获取帖子id
const page = query.page || 1; // 从query参数中获取页码,如果没获取到默认为1
const [topic, commentsResp] = await Promise.all([
$axios.get('/api/topic/' + topicId),
$axios.get('/api/comment/list', {
params: {
topicId: topicId,
page: page,
},
}),
]);
const maxPage =
commentsResp.totalCount % 20 > 0
? parseInt(commentsResp.totalCount / 20) + 1
: commentsResp.totalCount / 20;
return {
topic: topic,
comments: commentsResp.comments,
page: parseInt(page),
maxPage: maxPage,
};
},
methods: {
async createComment() {
try {
const resp = await this.$axios.post('/api/comment/add', {
topicId: this.topic.id,
content: this.commentContent,
});
// 计算跟帖的最大页码
this.maxPage =
resp.totalCount % 20 > 0
? parseInt(resp.totalCount / 20) + 1
: resp.totalCount / 20;
// 发表成功后清空输入框内容
this.commentContent = '';
// 将放发表的评论显示在列表中
if (!this.comments) {
this.comments = [];
}
this.comments.unshift(resp);
} catch (err) {
alert(err.message || err);
}
},
},
};
</script>
<style scoped>
article .title {
font-weight: bold;
font-size: 15px;
border-bottom: 2px #f7f8fb dashed;
padding-bottom: 10px;
}
article .title .meta {
font-weight: normal;
font-size: 12px;
color: #3b8070;
}
article .content {
margin-top: 10px;
}
.comments {
margin: 20px 0;
}
.comments .comment {
display: flex;
border-bottom: 2px solid #f7f8fb;
}
.comments .comment .avatar {
max-width: 50px;
max-height: 50px;
border-radius: 50%;
}
.comments .comment .comment-left {
margin-right: 10px;
}
.comments .comment .comment-right {
padding-top: 3px;
}
.comments .comment .comment-right .comment-content {
font-weight: bold;
}
.comments .comment .comment-right .comment-meta {
font-weight: bold;
font-size: 12px;
color: #3b8070;
}
</style>
帖子详情页中的跟帖是支持分页的,进去之后默认展示的是第一页的数据,如果要展示其他页码中的数据需要在 url 的 query 参数中指定页面,例如:/topic/1?page=2。Nuxt.js 中我们是通过 query 来获取页面的,如下:
async asyncData ({params, query, $axios}) {
const page = query.page || 1 // 从query参数中获取页码,如果没获取到默认为1
...
}
在该页面的asyncData方法中有两个异步操作:获取帖子详情,获取评论列表,当有多个异步操作的时候,我们可以通过Promise.all来并行执行这些异步操作,当他们都执行成功之后统一处理返回结果,例如:
async asyncData ({params, query, $axios}) {
...
const [topic, commentsResp] = await Promise.all([
$axios.get('/api/topic/' + topicId),
$axios.get('/api/comment/list', {
params: {
topicId: topicId,
page: page
}
})
])
...
}
接下来我们执行npm run dev命令来启动 site 项目,就能看到效果啦。
本实例中我们完成了跟帖功能。下面我们看下本实例完整源码的目录结构:
.
├── server
│ ├── comment_controller.go
│ ├── comment_model.go
│ ├── comment_service.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ ├── topic_controller.go
│ ├── topic_model.go
│ ├── topic_service.go
│ ├── user_controller.go
│ ├── user_model.go
│ └── user_service.go
└── site
├── README.md
├── assets
│ └── README.md
├── components
│ ├── Logo.vue
│ ├── MyFooter.vue
│ ├── MyNav.vue
│ └── README.md
├── jsconfig.json
├── layouts
│ ├── README.md
│ └── default.vue
├── middleware
│ └── README.md
├── nuxt.config.js
├── package-lock.json
├── package.json
├── pages
│ ├── README.md
│ ├── index.vue
│ ├── topic
│ │ ├── _id.vue
│ │ └── create.vue
│ ├── topics
│ │ └── _page.vue
│ └── user
│ ├── login.vue
│ └── reg.vue
├── plugins
│ ├── README.md
│ └── axios.js
├── static
│ ├── README.md
│ └── favicon.ico
└── store
└── README.md