vue近来是前端最热门的框架之一,不久之前,在做项目的时候,遇到一个问题,就是vue组件递归的问题,经过研究,总结出以下几点,若有不同见解,欢迎各位大佬纠正.
一.需求实现(这里用的是vue的脚手架搭建的项目总体框架)
各大论坛,相信大家都知道,其中针对每个人发的帖子需要进行回复的操作,针对第一个人回复的内容,第二个回复人也可以回复第一个人的回复,依次类推,这就需要递归显示每条帖子后面的所有评论信息,下面我们就一起来看看实现的方式
二.组件的创建
首先,在项目中新建一个组件,这里我命名为set.vue(名字随便起的,不要在意),在main.js中导入
书写set.vue的内容模板(注:set.vue这个组件就是用于显示论坛帖子评论的组件)
这个是论坛的模板部分,其中responseTopic是个数组,我们一起来看看这个数组的结构是怎么样的
replyList: [
{
id:
5,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:29:20",
content:
"+1+1+1+1+1+1+1+1+1+1",
anonymous:
"0",
replyList: [
{
id:
8,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:52:35",
content:
"+1+2+3",
anonymous:
"0",
replyList:
null
}
]
}
]
},
{
id:
6,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:46:03",
content:
"+1+2+3",
anonymous:
"0",
replyList:
null
},
{
id:
7,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:50:51",
content:
"+1+2+3",
anonymous:
"0",
replyList:
null
}
]
可以看到这些数据将来是后台接口返回给我们的,每一层数据,对应一条用户的评论,我门需要对这些数据进行递归展示,就必须要考虑到数据的合理性和共性,观察这些数据我们可以看到每一层都是相同的字段,并且有一个顶层数据,这就让我想到,要想把这些数据全部展示到页面上,单纯的v-for是不够的,因为你不知道,将来这里面到底有多少层数据,接下来,我就根据数据来介绍一下,vue组件之间的通讯原理.
我们知道,vue父子组件之间通讯,若父组件想把自己本身的数据发送到子组件身上,就必须要在引用子组件的时候通过vue的数据绑定v-bind(或者':')将需要的数据绑定到子组件身上,本例中在引用子组件的时候,通过绑定
:responseTopic="
responseTopic"
把自身上的数据传递到子组件内部,子组件要想拿到父组件传过来的数据,就必须要定义一个叫props的对象或者数组
,然后把父组件中绑定的数据定义到这里面,就可以直接使用了 . 下面这是我在home.vue页面中(也就是用于显示评论组件的父组件)引用刚刚创建的组件,我们知道一个组件只能展示一条用户评论,那么,怎么才能让组件展示出所有的数据呢?通过上面的观察的数据结构发现,只要每层数据中有replyList字段,就证明,这层评论下面还有评论,那么既然这样的话,我们可以在刚刚创建的set.vue这个组件中,引入自己,见下图
对的,你没看错,就是自己引用自己,根据数据结构,一层结构对应一层数据,每层需要的数据,已经通过vue组件绑定数据传递到了它的子组件身上,而组件嵌套,正好对应了每层数据结构,它的作用也就是解析所有层的评论对象,到这里,你应该会问,那么一直这样嵌套下去,不会导致死循环嘛,是的,如果真的一直循环下去不管在强大的框架也是吃不消的,这时候,就需要我们有一个停止嵌套的条件,这里我用的是v-if,v-if后面的表达式为true时才会显示,也就是说当replyList为null或''时,就不会继续嵌套下去了,这就达到我所要的效果,下图是该案例实现的效果图
下面贴出该案例完整代码
1.路由配置页面
2.home.vue页面
<
script
>
import
set
from
"./set.vue";
export
default {
data() {
return {
isAdmin:
false,
scrollTop:
0,
isShow:
false,
isActive:
false,
isTop:
false,
pageSizes: [
10,
20,
30,
40],
pageSize:
10,
currentPage:
1,
total:
0,
topicId:
this.
$route.
query.
topicId,
defaultMsg:
"请输入回复内容",
topicDetail: [],
//存放帖子详情数据
responseTopic: [
{
id:
1,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 14:51:58",
content:
"这帖子为ID为1的第一条评论",
anonymous:
"0",
replyList: [
{
id:
4,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:08:43",
content:
"不要沉,我给你顶起来。",
anonymous:
"0",
replyList: [
{
id:
5,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:29:20",
content:
"+1+1+1+1+1+1+1+1+1+1",
anonymous:
"0",
replyList: [
{
id:
8,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:52:35",
content:
"+1+2+3",
anonymous:
"0",
replyList:
null
}
]
}
]
},
{
id:
6,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:46:03",
content:
"+1+2+3",
anonymous:
"0",
replyList:
null
},
{
id:
7,
cusomer: {
id:
1,
aliasName:
null,
nickName:
null,
realName:
null,
loginName:
null,
status:
null
},
createTime:
"2018-06-30 15:50:51",
content:
"+1+2+3",
anonymous:
"0",
replyList:
null
}
]
}
],
//存放回复帖子列表
};
},
methods: {
// 控制收藏逻辑
show() {
this.
isActive = !
this.
isActive;
},
handleSizeChange() {},
handleCurrentChange() {}
},
components: {
set
}
};
</
script
>
<
style
scoped
>
.forum-container {
width:
80%;
margin:
0
auto;
padding:
2%
6%;
clear:
both;
position:
relative;
}
.forum-all .blocks {
position:
fixed;
margin-left:
81%;
margin-top:
10%;
z-index:
99;
transition:
all
ease
0.8s;
}
.forum-all .blocks span {
display:
block;
width:
40px;
height:
40px;
font:
14px
"microsoft yahei";
color:
#fff;
z-index:
1;
box-sizing:
border-box;
margin-bottom:
10px;
text-align:
center;
cursor:
pointer;
}
.forum-all .blocks span.one {
line-height:
40px;
background-color:
#10a386;
}
.forum-all .blocks span.two {
line-height:
40px;
background-color:
#0084ff;
}
.forum-all .blocks span.three {
background-color:
#008fd5;
}
.forum-all .blocks span.back {
/* margin-top: 350px; */
background-color:
#008fd5;
}
.toTOP {
margin-top:
-10%
!important;
}
.forum-all {
width:
100%;
background-color:
#fff;
border:
1px
solid
#eee;
overflow:
hidden;
position:
relative;
}
.forum-all .btn {
float:
right;
box-sizing:
border-box;
position:
absolute;
top:
8px;
right:
26px;
}
/* ????��???? */
.fontcolorblue {
color:
#0285ff;
}
.imgBg-skyblue-radius {
display:
block;
width:
40px;
height:
40px;
background-color:
#86c0e4;
position:
relative;
border-radius:
50%;
}
.colorblue {
color:
#369eff;
}
.colorgreen {
color:
#42b69f;
}
.colorred {
color:
#e04639;
}
/* ???��???? */
.breadLink {
width:
40%;
/* padding: 20px 20px */
}
/* ???????? */
.detaiContent {
width:
70%;
overflow:
hidden;
padding:
0
20px;
float:
left;
}
.detaiContent .intro {
width:
100%;
padding:
20px;
border:
1px
solid
#eee;
overflow:
hidden;
box-sizing:
border-box;
margin-bottom:
20px;
}
.detaiContent .intro .introtitle {
width:
100%;
overflow:
hidden;
border-bottom:
1px
solid
#eee;
}
.detaiContent .intro .left {
width:
60%;
float:
left;
}
.detaiContent .intro .left h1 {
margin:
0;
font:
16px
"microsoft yahei";
text-align:
left;
position:
relative;
}
.detaiContent .intro .left h1 div.subtitle {
position:
absolute;
top:
0;
left:
70%;
}
.detaiContent .intro .left h1 div.subtitle span {
display:
block;
text-align:
center;
font:
12px
"microsoft yahei";
color:
#fff;
line-height:
24px;
width:
60px;
float:
left;
margin:
0;
border-radius:
8px;
}
.detaiContent .intro .left h1 div.subtitle span.top {
background-color:
#0084ff;
}
.detaiContent .intro .left h1 div.subtitle span.main {
margin-left:
8px;
background-color:
#ff3040;
}
.detaiContent .intro .left p {
text-align:
left;
}
.detaiContent .intro .left p span {
font:
14px/
28px
"microsoft yahei";
}
.detaiContent .intro .left p span i {
font-style:
normal;
color:
#0084ff;
margin-left:
8px;
}
/* .detaiContent .intro .left p span.distance {
margin-left: 8px
} */
.detaiContent .intro .right {
float:
right;
text-align:
right;
}
.detaiContent .intro .right .star {
display:
block;
width:
32px;
height:
32px;
font:
24px/
32px
"microsoft yahei";
text-align:
center;
background-color:
#f2f4f7;
margin-left:
86px;
cursor:
pointer;
}
.fontcolororange {
color:
#ffba00;
}
.detaiContent .intro .right .operator {
font:
14px/
28px
"microsoft yahei";
}
/* .detaiContent .intro .right .operator span.distance {
margin-left: 14px;
} */
.detaiContent .intro .introbody {
width:
100%;
padding-top:
28px;
}
.detaiContent .intro .introbody h3 {
font:
14px/
28px
"microsoft yahei";
text-align:
left;
}
.detaiContent .intro .introbody .desc {
font:
14px/
28px
"microsoft yahei";
text-align:
left;
text-indent:
2em;
margin-bottom:
20px;
}
.detaiContent .comment {
width:
100%;
/* padding: 20px; */
border:
1px
solid
#eee;
overflow:
hidden;
box-sizing:
border-box;
margin-bottom:
20px;
}
.invitation-content {
width:
100%;
/* border: 1px solid #eee; */
overflow:
hidden;
/* margin-bottom: 40px; */
}
.invitation-title {
width:
100%;
padding:
10px
10px;
height:
40px;
line-height:
40px;
overflow:
hidden;
position:
relative;
border-bottom:
1px
solid
#eee;
box-sizing:
border-box;
}
.invitation-title span {
width:
60px;
display:
inline-block;
cursor:
pointer;
float:
left;
text-align:
center;
font:
14px
"microsoft yahei";
}
.invitation-title #new {
border-right:
1px
solid
#eee;
}
.active {
color:
#0084ff;
/* background-color: #0084ff; */
}
.comment-bodys {
width:
100%;
/* overflow: hidden;
padding: 0 20px;
box-sizing: border-box */
}
.comment-body {
width:
100%;
overflow:
hidden;
padding:
0
20px;
box-sizing:
border-box;
}
.comment-body-first {
width:
100%;
overflow:
hidden;
padding:
0
0
0
30px;
box-sizing:
border-box;
}
.invitation-body {
width:
100%;
height:
80px;
padding:
20px;
border-bottom:
1px
solid
#eee;
box-sizing:
border-box;
overflow:
hidden;
}
.head-portrait {
width:
10%;
float:
left;
text-align:
left;
padding-left:
10px;
}
.head-portrait img {
position:
absolute;
top:
5px;
left:
5px;
width:
30px;
height:
30px;
border-radius:
50%;
}
.theme {
width:
53%;
margin-left:
2%;
float:
left;
margin:
0;
text-align:
left;
}
.theme .commendtitle {
font:
14px
"microsoft yahei";
text-align:
left;
margin:
0;
cursor:
pointer;
}
.theme p {
font:
12px
"microsoft yahei";
margin-top:
6px;
text-align:
left;
}
.theme p span.distance i {
color:
skyblue;
}
.distance {
margin-left:
8px;
}
.state {
float:
right;
}
.state .floor {
display:
block;
text-align:
right;
font:
14px/
20px
"microsoft yahei";
}
.state .commendoperator {
}
.state .commendoperator span {
display:
block;
float:
left;
cursor:
pointer;
font:
14px/
20px
"microsoft yahei";
}
.footerPage {
padding-right:
10px;
}
.footerPage .el-pagination {
margin:
20px
0;
float:
right;
}
.publish {
width:
100%;
padding:
10px
10px
10px
60px;
box-sizing:
border-box;
border:
1px
solid
#eee;
overflow:
hidden;
position:
relative;
margin-bottom:
20px;
}
.uedit {
margin-bottom:
10px;
}
.btnGroup {
width:
100px;
}
.user-portrait {
position:
absolute;
top:
16px;
left:
4px;
}
.user-portrait img {
width:
40px;
height:
40px;
border-radius:
50%;
}
.detailRight {
width:
26%;
float:
left;
padding:
0
20px
0
0;
box-sizing:
border-box;
/* margin-right: 1%; */
}
.detailRight .usercontent {
width:
100%;
border:
1px
solid
#eee;
box-sizing:
border-box;
margin-bottom:
10px;
}
.detailRight .usercontent .userImage {
background-color:
#ebeef5;
width:
70px;
height:
70px;
border-radius:
50%;
box-sizing:
border-box;
padding-top:
5px;
margin:
20px
auto;
}
.detailRight .usercontent .userImage img {
width:
60px;
height:
60px;
border-radius:
50%;
cursor:
pointer;
}
.detailRight .usercontent .userbody {
width:
100%;
margin:
0
auto;
overflow:
hidden;
display:
flex;
justify-content:
center;
margin-bottom:
40px;
}
.detailRight .usercontent .userbody span {
display:
block;
width:
60px;
font:
14px
"microsoft yahei";
text-align:
center;
float:
left;
cursor:
pointer;
}
.detailRight .usercontent .userbody span.border {
border-right:
1px
solid
#eee;
}
.detailRight .usercontent .userbody span i {
font-style:
normal;
color:
#2d97ff;
}
.detailRight .usercontent h3 {
font:
600
14px
"microsoft yahei";
}
.detailRight .dynamic {
border:
1px
solid
#eee;
box-sizing:
border-box;
}
.detailRight .dynamic h3 {
height:
40px;
background-color:
#f7f8fa;
font:
600
14px/
28px
"microsoft yahei";
line-height:
40px;
text-align:
center;
margin:
0;
border-bottom:
1px
solid
#eee;
}
.detailRight .dynamic .article span {
display:
block;
font:
14px
"microsoft yahei";
cursor:
pointer;
height:
40px;
line-height:
40px;
text-align:
center;
border-bottom:
1px
solid
#eee;
}
.detailRight .dynamic .article span:last-of-type {
border-bottom:
none;
}
.detailRight .dynamic .article span:hover {
color:
#0084ff;
text-decoration:
underline;
}
</
style
>
3.set.vue(评论组件)页面
</
script
>
<
style
scoped
>
.forum-container {
width:
80%;
margin:
0
auto;
padding:
2%
6%;
clear:
both;
position:
relative;
}
.forum-all .blocks {
position:
fixed;
margin-left:
81%;
margin-top:
10%;
z-index:
99;
transition:
all
ease
0.8s;
}
.forum-all .blocks span {
display:
block;
width:
40px;
height:
40px;
font:
14px
"microsoft yahei";
color:
#fff;
z-index:
1;
box-sizing:
border-box;
margin-bottom:
10px;
text-align:
center;
cursor:
pointer;
}
.forum-all .blocks span.one {
line-height:
40px;
background-color:
#10a386;
}
.forum-all .blocks span.two {
line-height:
40px;
background-color:
#0084ff;
}
.forum-all .blocks span.three {
background-color:
#008fd5;
}
.forum-all .blocks span.back {
/* margin-top: 350px; */
background-color:
#008fd5;
}
.toTOP {
margin-top:
-10%
!important;
}
.forum-all {
width:
100%;
background-color:
#fff;
border:
1px
solid
#eee;
overflow:
hidden;
position:
relative;
}
.forum-all .btn {
float:
right;
box-sizing:
border-box;
position:
absolute;
top:
8px;
right:
26px;
}
/* ????��???? */
.fontcolorblue {
color:
#0285ff;
}
.imgBg-skyblue-radius {
display:
block;
width:
40px;
height:
40px;
background-color:
#86c0e4;
position:
relative;
border-radius:
50%;
}
.colorblue {
color:
#369eff;
}
.colorgreen {
color:
#42b69f;
}
.colorred {
color:
#e04639;
}
/* ???��???? */
.breadLink {
width:
40%;
/* padding: 20px 20px */
}
/* ???????? */
.detaiContent {
width:
70%;
overflow:
hidden;
padding:
0
20px;
float:
left;
}
.detaiContent .intro {
width:
100%;
padding:
20px;
border:
1px
solid
#eee;
overflow:
hidden;
box-sizing:
border-box;
margin-bottom:
20px;
}
.detaiContent .intro .introtitle {
width:
100%;
overflow:
hidden;
border-bottom:
1px
solid
#eee;
}
.detaiContent .intro .left {
width:
60%;
float:
left;
}
.detaiContent .intro .left h1 {
margin:
0;
font:
16px
"microsoft yahei";
text-align:
left;
position:
relative;
}
.detaiContent .intro .left h1 div.subtitle {
position:
absolute;
top:
0;
left:
70%;
}
.detaiContent .intro .left h1 div.subtitle span {
display:
block;
text-align:
center;
font:
12px
"microsoft yahei";
color:
#fff;
line-height:
24px;
width:
60px;
float:
left;
margin:
0;
border-radius:
8px;
}
.detaiContent .intro .left h1 div.subtitle span.top {
background-color:
#0084ff;
}
.detaiContent .intro .left h1 div.subtitle span.main {
margin-left:
8px;
background-color:
#ff3040;
}
.detaiContent .intro .left p {
text-align:
left;
}
.detaiContent .intro .left p span {
font:
14px/
28px
"microsoft yahei";
}
.detaiContent .intro .left p span i {
font-style:
normal;
color:
#0084ff;
margin-left:
8px;
}
/* .detaiContent .intro .left p span.distance {
margin-left: 8px
} */
.detaiContent .intro .right {
float:
right;
text-align:
right;
}
.detaiContent .intro .right .star {
display:
block;
width:
32px;
height:
32px;
font:
24px/
32px
"microsoft yahei";
text-align:
center;
background-color:
#f2f4f7;
margin-left:
86px;
cursor:
pointer;
}
.fontcolororange {
color:
#ffba00;
}
.detaiContent .intro .right .operator {
font:
14px/
28px
"microsoft yahei";
}
/* .detaiContent .intro .right .operator span.distance {
margin-left: 14px;
} */
.detaiContent .intro .introbody {
width:
100%;
padding-top:
28px;
}
.detaiContent .intro .introbody h3 {
font:
14px/
28px
"microsoft yahei";
text-align:
left;
}
.detaiContent .intro .introbody .desc {
font:
14px/
28px
"microsoft yahei";
text-align:
left;
text-indent:
2em;
margin-bottom:
20px;
}
.detaiContent .comment {
width:
100%;
/* padding: 20px; */
border:
1px
solid
#eee;
overflow:
hidden;
box-sizing:
border-box;
margin-bottom:
20px;
}
.invitation-content {
width:
100%;
/* border: 1px solid #eee; */
overflow:
hidden;
/* margin-bottom: 40px; */
}
.invitation-title {
width:
100%;
padding:
10px
10px;
height:
40px;
line-height:
40px;
overflow:
hidden;
position:
relative;
border-bottom:
1px
solid
#eee;
box-sizing:
border-box;
}
.invitation-title span {
width:
60px;
display:
inline-block;
cursor:
pointer;
float:
left;
text-align:
center;
font:
14px
"microsoft yahei";
}
.invitation-title #new {
border-right:
1px
solid
#eee;
}
.active {
color:
#0084ff;
/* background-color: #0084ff; */
}
.comment-bodys {
width:
100%;
/* overflow: hidden;
padding: 0 20px;
box-sizing: border-box */
}
.comment-body {
width:
100%;
overflow:
hidden;
padding:
0
20px;
box-sizing:
border-box;
}
.comment-body-first {
width:
100%;
overflow:
hidden;
padding:
0
0
0
30px;
box-sizing:
border-box;
}
.invitation-body {
width:
100%;
height:
80px;
padding:
20px;
border-bottom:
1px
solid
#eee;
box-sizing:
border-box;
overflow:
hidden;
}
.head-portrait {
width:
10%;
float:
left;
text-align:
left;
padding-left:
10px;
}
.head-portrait img {
position:
absolute;
top:
5px;
left:
5px;
width:
30px;
height:
30px;
border-radius:
50%;
}
.theme {
width:
53%;
margin-left:
2%;
float:
left;
margin:
0;
text-align:
left;
}
.theme .commendtitle {
font:
14px
"microsoft yahei";
text-align:
left;
margin:
0;
cursor:
pointer;
}
.theme p {
font:
12px
"microsoft yahei";
margin-top:
6px;
text-align:
left;
}
.theme p span.distance i {
color:
skyblue;
}
.distance {
margin-left:
8px;
}
.state {
float:
right;
}
.state .floor {
display:
block;
text-align:
right;
font:
14px/
20px
"microsoft yahei";
}
.state .commendoperator {
}
.state .commendoperator span {
display:
block;
float:
left;
cursor:
pointer;
font:
14px/
20px
"microsoft yahei";
}
.footerPage {
padding-right:
10px;
}
.footerPage .el-pagination {
margin:
20px
0;
float:
right;
}
.publish {
width:
100%;
padding:
10px
10px
10px
60px;
box-sizing:
border-box;
border:
1px
solid
#eee;
overflow:
hidden;
position:
relative;
margin-bottom:
20px;
}
.uedit {
margin-bottom:
10px;
}
.btnGroup {
width:
100px;
}
.user-portrait {
position:
absolute;
top:
16px;
left:
4px;
}
.user-portrait img {
width:
40px;
height:
40px;
border-radius:
50%;
}
.detailRight {
width:
26%;
float:
left;
padding:
0
20px
0
0;
box-sizing:
border-box;
/* margin-right: 1%; */
}
.detailRight .usercontent {
width:
100%;
border:
1px
solid
#eee;
box-sizing:
border-box;
margin-bottom:
10px;
}
.detailRight .usercontent .userImage {
background-color:
#ebeef5;
width:
70px;
height:
70px;
border-radius:
50%;
box-sizing:
border-box;
padding-top:
5px;
margin:
20px
auto;
}
.detailRight .usercontent .userImage img {
width:
60px;
height:
60px;
border-radius:
50%;
cursor:
pointer;
}
.detailRight .usercontent .userbody {
width:
100%;
margin:
0
auto;
overflow:
hidden;
display:
flex;
justify-content:
center;
margin-bottom:
40px;
}
.detailRight .usercontent .userbody span {
display:
block;
width:
60px;
font:
14px
"microsoft yahei";
text-align:
center;
float:
left;
cursor:
pointer;
}
.detailRight .usercontent .userbody span.border {
border-right:
1px
solid
#eee;
}
.detailRight .usercontent .userbody span i {
font-style:
normal;
color:
#2d97ff;
}
.detailRight .usercontent h3 {
font:
600
14px
"microsoft yahei";
}
.detailRight .dynamic {
border:
1px
solid
#eee;
box-sizing:
border-box;
}
.detailRight .dynamic h3 {
height:
40px;
background-color:
#f7f8fa;
font:
600
14px/
28px
"microsoft yahei";
line-height:
40px;
text-align:
center;
margin:
0;
border-bottom:
1px
solid
#eee;
}
.detailRight .dynamic .article span {
display:
block;
font:
14px
"microsoft yahei";
cursor:
pointer;
height:
40px;
line-height:
40px;
text-align:
center;
border-bottom:
1px
solid
#eee;
}
.detailRight .dynamic .article span:last-of-type {
border-bottom:
none;
}
.detailRight .dynamic .article span:hover {
color:
#0084ff;
text-decoration:
underline;
}
</
style
>
所有评论(0)