文章评论
#1、业务功能分析
#2、展示文章评论列表
#2.1、准备组件
为了更好的开发和维护,这里我们把文章评论单独封装到一个组件中来处理。
创建组件 src/views/article/components/comment-list.vue
<template>
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<van-cell v-for="item in list" :key="item" :title="item"></van-cell>
</van-list>
</template>
<script>
export default {
name: "CommentList",
components:{},
props: {},
data() {
return {
list: [], // 评论列表
loading: false, // 上拉加载更多的 loading
finished: false // 是否加载结束
};
},
methods: {
onLoad() {
// 异步更新数据
setTimeout(() => {
for (let i = 0; i < 10; i++) {
this.list.push(this.list.length + 1);
}
// 加载状态结束
this.loading = false;
// 数据全部加载完成
if (this.list.length >= 40) {
this.finished = true;
}
}, 500);
}
}
};
</script>
article/index.vue
导入、注册、使用组件
import CommentList from './components/comment-list'
components:{
// 其他注册...
CommentList
}
<van-divider>正文结束</van-divider>
<!------------------------------ 文章评论列表-------------------------------------->
<comment-list/>
<!------------------------------ /文章评论列表 ------------------------------------->
#2.2、获取数据并展示
提示:有评论数据的文章 id :短文章==>1323981393964826624, 长文章==>138671
步骤:
- 封装接口
- 请求获取数据
- 处理模板
实现:
1、在 api/comment.js
中添加封装请求方法
/**
* 评论请求模块
*/
import request from '@/utils/request'
/**
* 获取文章评论列表
*/
export const getComments = params => {
return request({
method: 'GET',
url: '/v1_0/comments',
params
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2、请求获取数据
-
父组件
article/index.vue
传入文章id<comment-list :source="article.art_id"/>
1
-
子组件
commnent-list
定义自定义属性接收props: { source: { type: [Number, String, Object], required: true } }
1
2
3
4
5
6 -
导入请求方法
import { getComments } from '@/api/comment'
1
-
定义相关变量
data(){ return{ //其他变量.. offset: null, // 获取下一页数据的标记 limit: 10, error: false } }
1
2
3
4
5
6
7
8 -
书写处理事件函数
methods: { async onLoad () { try { // 1. 请求获取数据 const { data } = await getComments({ type: 'a', // 评论类型,a-对文章(article)的评论,c-对评论(comment)的回复 source: this.source.toString(), // 源id,文章id或评论id,【可能有大数字,所以执行一下toString 方法】 offset: this.offset, // 评论数据的偏移量,值为评论id,表示从此id的数据向后取,不传表示从第一页开始读取数据 limit: this.limit // 获取的评论数据个数,不传表示采用后端服务设定的默认每页数据量 }) // 2. 将数据添加到列表中(一定要注意是追加数据,否则列表高度不增加,形成死循环) const { results } = data.data this.list.push(...results) // 3. 将 loading 设置为 false this.loading = false // 4. 判断是否还有数据 if (results.length) { // 有就更新获取下一页的数据页码 this.offset = data.data.last_id } else { // 没有就将 finished 设置结束 this.finished = true } } catch (err) { this.error = true this.loading = false } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 -
显示评论内容
<van-cell v-for="(item,index) in list" :key="index" :title="item.content"></van-cell>
1
#2.3、展示文章评论总数量
子组件comment-list.vue
触发自定义事件
-
onLoad
事件函数里面 触发自定义
// 2. 将数据添加到列表中 const { results } = data.data this.list.push(...results) // 把文章评论的总数量传递到外部 this.$emit('onload-success', data.data) // <========== 增加这一句 // 3. 将 loading 设置为 false this.loading = false
1
2
3
4
5
6
7
8
9 -
默认情况下只有滚动到了评论列表区域才会触发
onLoad
事件,所以我们需要再created
里面主动触发一次,保证一开始就触发created () { this.onLoad() }
1
2
3
父组件article/index.vue
中监听自定事件
-
定义变量存放总数量
data(){ //其他变量... totalCommentCount:0 // 文章评论总数量 }
1
2
3
4 -
绑定给展示组件的属性
<van-icon class="comment-icon" name="comment-o" :info="totalCommentCount" />
1
2
3
4
5 -
监听自定义事件,赋值给变量
<!-- 文章评论列表 --> <comment-list :source="article.art_id" @onload-success="totalCommentCount = $event.total_count" /> <!-- /文章评论列表 -->
1
2
3
4
5
6
#2.4、文章评论项
创建 article/components/comment-item.vue
<template>
<van-cell class="comment-item">
<van-image
slot="icon"
class="avatar"
round
fit="cover"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
<div slot="title" class="title-wrap">
<div class="user-name">用户名称</div>
<van-button
class="like-btn"
icon="good-job-o"
>赞</van-button>
</div>
<div slot="label">
<p class="comment-content">这是评论内容</p>
<div class="bottom-info">
<span class="comment-pubdate">4天前</span>
<van-button
class="reply-btn"
round
>回复 0</van-button>
</div>
</div>
</van-cell>
</template>
<script>
export default {
name: 'CommentItem',
props: {
//每行的评论信息
comment: {
type: Object,
required: true
}
},
methods: {}
}
</script>
<style scoped lang="less">
.comment-item {
.avatar {
width: 72px;
height: 72px;
margin-right: 25px;
}
.title-wrap {
display: flex;
justify-content: space-between;
align-items: center;
.user-name {
color: #406599;
font-size: 26px;
}
}
.comment-content {
font-size: 32px;
color: #222222;
word-break: break-all;
text-align: justify;
}
.comment-pubdate {
font-size: 19px;
color: #222;
margin-right: 25px;
}
.bottom-info {
display: flex;
align-items: center;
}
.reply-btn {
width: 135px;
height: 48px;
line-height: 48px;
font-size: 21px;
color: #222;
}
.like-btn {
height: 30px;
padding: 0;
border: none;
font-size: 19px;
line-height: 30px;
margin-right: 7px;
.van-icon {
font-size: 30px;
}
}
.liked{
background-color:orange;
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47