向全栈迈进——Angular+Tornado开发树洞博客(九)

本文详细介绍了如何在Angular应用中实现故事列表与评论功能,包括前端组件设计、数据交互与后端API开发。通过Ng-ZORRO组件和自定义模块,展示了如何展示故事详情、评论数据及实现点赞等功能。

在上一篇博客中,我们建立了story模块,并在其中完成了书写故事功能的开发。在这篇博客中,我们将实现首页上展示的故事列表,并开始开发评论功能。

十二 故事列表的开发

1 前端部分

我们需要建立一个home组件作为我们呈现故事列表的地方。我们打开cmd,输入以下命令,建立一个home组件:

ng g c home

然后,我们在app.module.ts中引入NG-ZORRO提供的标签组件,以便在之后对故事进行分类展示:

//app.module.ts
//...
import { NzTabsModule } from 'ng-zorro-antd/tabs';
//...

@NgModule({
  declarations: [
  //...
  ],
  imports: [
	//...
    NzTabsModule,
    //...
  ],
  providers: [CookieService],
  bootstrap: [AppComponent]
})
export class AppModule { }

接下来,我们打开home.component.html,输入以下代码:

<!--home.component.html-->
<nz-tabset>
    <nz-tab nzTitle="全部">
      <app-storylist></app-storylist>
    </nz-tab>
    <nz-tab nzTitle="Tab 2">
      Content of Tab Pane 2
    </nz-tab>
    <nz-tab nzTitle="Tab 3">
      Content of Tab Pane 3
    </nz-tab>
</nz-tabset>

这里的app-storylist是我们稍后要建立的故事列表组件,如果想看效果的话,可以暂时把它替换为其他东西。
然后,我们将home组件加到路由列表中:

//app-routing.module.ts
//..
const routes: Routes = [
	//..
  {path:'',component:HomeComponent},
  //..
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

这样,我们的主页就会出现一个带标签页的空白页面:
在这里插入图片描述
下一步,让我们继续在story模块中实现我们的storylist组件。在cmd中输入如下命令,建立storylist组件:

ng g c storylist -m story

在这个组件中我们要展示两部分数据:第一部分是故事的基本信息,第二部分是和故事有关的所有评论,因此我们需要在这个组件中定义两个接口storyDetail和commentData:

//story/storylist/commentData.ts
export interface commentData {
    author:string;
    content: string;
    commentBody:string;
  }
  • author:故事作者。
  • content:故事内容。
  • commentBody:评论体,意思是这条评论是属于哪个故事或者评论的。
//story/storylist/storyDetail.ts
export interface storyDetail {
    id:number;
    author:string;
    title: string;
    content: string;
    publishdate:string;
    commentCount:string;
    externalId:string;
  }
  • id:故事Id。
  • author:故事作者
  • title:故事标题
  • content:故事内容
  • publishdate:发布日期
  • commentCount:评论数
  • externalId:外部Id,如果为故事的话,其格式为’doc_‘加当前时间;如果为评论的话,其格式为’cmt_'加当前时间。此Id将在之后的评论树开发中使用。

然后,我们需要在story.module.ts中引入以下模块:

//story.moddule.ts
//..
import { NzDividerModule } from 'ng-zorro-antd/divider';
import { NzSpaceModule } from 'ng-zorro-antd/space';
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { IconDefinition } from '@ant-design/icons-angular';
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
import { NzCommentModule } from 'ng-zorro-antd/comment';
import { NzAvatarModule } from 'ng-zorro-antd/avatar';

import { StarOutline, CommentOutline, LikeOutline } from '@ant-design/icons-angular/icons';
import { CommentsComponent } from './comments/comments.component';
import { CommentformComponent } from './commentform/commentform.component';
import { NzListModule } from 'ng-zorro-antd/list';

const icons: IconDefinition[] = [ StarOutline, CommentOutline, LikeOutline ];
@NgModule({
  declarations: [
	//..
  ],
  imports: [
  	//...
    NzDividerModule,
    NzSpaceModule,
    NzCardModule,
    NzIconModule.forRoot(icons),
    NzCollapseModule,
    NzCommentModule,
    NzAvatarModule,
    NzListModule
  ],
  exports:[StorylistComponent]
})
export class StoryModule { }

  • NzDividerModule:分割线模块,用于分割文字。
  • NzSpaceModule:间距模块,用于设置组件之间的间距,防止组件之间紧贴在一起。
  • NzCardModule:卡片容器,可以承载文字、图片等基础内容。
  • NzIconModule:NG-ZORRO提供的图标库。
  • NzCollapseModule:折叠面板组件
  • NzCommentModule:NG-ZORRO提供的评论框组件,是我们评论树的基础组件,提供了常用评论的基础功能,如点赞、点踩、回复,甚至还提供了一个回复用户的头像。其组件效果如下所示:
    在这里插入图片描述
  • NzAvatarModule:头像组件,就是上图左边那个人头。
  • NzListModule:列表组件,以列表方式展示内容。
    在引入了以上模块后,我们就可以开始编写storylist的前端部分了。打开storylist.component.html文件,输入如下代码:
<!--storylist.component.html-->
<div *ngFor="let story of storyList" >
    <nz-card nzTitle="{{story.title}}" >
        <div innerHtml='{{story.content}}'></div>
    </nz-card>
	<nz-card>
    <nz-space>
    <span *nzSpaceItem><i nz-icon nzType="star" nzTheme="outline"></i> 收藏</span>
    <span *nzSpaceItem ><i nz-icon nzType="comment" nzTheme="outline"></i><a> 评论</a> </span>
    <span *nzSpaceItem><i nz-icon nzType="like" nzTheme="outline"></i> 喜欢</span>
    </nz-space>
    </nz-card>
    <br>
</div>

这个故事列表的结构比较简单,就是用card的方式来列出所有后端服务器返回的数据。值得注意的是,由于我们使用的是富文本编辑器来存放故事,因此在展示故事内容时要使用innerHtml属性,而不能直接将内容放在标签内部,否则会无法显示出富文本的格式。
然后,我们打开storylist.component.ts文件,开始编写前端的逻辑部分:

//storylist.component.ts
import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { StoryService } from 'src/app/service/story.service';
import { storyDetail } from './storeDetail';
import { FormControl,FormGroup } from '@angular/forms';

@Component({
  selector: 'app-storylist',
  templateUrl: './storylist.component.html',
  styleUrls: ['./storylist.component.scss']
})
export class StorylistComponent implements OnInit {
  storyList:storyDetail[];
  constructor(private storyService:StoryService) {
    this.storyList = [];
    this.showAllStory();
   }
  ngOnInit(): void {

  }
  showAllStory(){
    this.storyService.showAllStory().subscribe((data:any) => {
      if (data)
      {
        data['storylist'].forEach((element:storyDetail) => {
          this.storyList.push({
            'id':element['id'],
            'title':element['title'],
            'content':element['content'],
            'author':element['author'],
            'publishdate':element['publishdate'],
            'commentCount':element['commentCount'],
            'externalId':element['externalId']
          })
        });
      }
    })
  }
}

现在的前端逻辑包含了一个storyService对象以及一个storyDetail列表,我们会在showAllStory函数中通过storyService对象拿到所有故事的数据,再将其存放到storyDetail列表中,从而在前端展示出来。
然后,我们打开story.service.ts文件,实现service中的showAllStory函数:

//service/story.service.ts
//...
@Injectable({
  providedIn: 'root'
})
export class StoryService {

  constructor(private http:HttpClient) { }
  //...
  showAllStory(){
    return this.http.get('http://localhost:8000/getallstory')
  }
}

这样,我们就完成了故事列表组件的前端部分。下面,让我们继续来实现故事列表的后端部分开发。

2 后端部分

我们打开story_comment_app.py,实现GetAllStory类:

# server/apps/story_comment_app/story_comment_app.py
class GetAllStory(BaseHandler):
    def get(self):
        allstory = session.query(Storys).all()
        allstorylist = []
        for story in allstory:
            story_dir = {
                'id':story.id,
                'title':story.title,
                'content':story.content,
                'author':story.author,
                'publishdate':story.publishDate.__str__(),
                'commentCount':story.commentCount,
                'externalId':story.externalId
            }
            allstorylist.append(story_dir)
        storylist = {'storylist':allstorylist}
        self.write(json.dumps(storylist))

这个函数没什么说的,当前的逻辑就是将Storys表中的所有数据都列出来,然后以字典的形式存放在list中,再将list以json的方式返回给前端即可。
最后,我们再将GetAllStory加到后端路由中:

# server/main.py
# ...
    routelist = [
		# ...
        (r"/getallstory",GetAllStory),
        # ...
    ]
# ...

这样,我们就完成了故事列表的开发,我们现在应该可以在首页中看到我们已发布的故事了:
在这里插入图片描述
接下来,让我们进入重头戏——评论系统的开发。

十三 评论系统的开发

1 评论系统结构

我们首先来看一下这个评论系统的结构:
在这里插入图片描述

从上图可知,在展开的评论树中,每篇故事可以有多个评论,而对于每个评论来说,又可以分别对其进行新的评论,并以缩进方式显示在其下方。这就需要我们实现一个嵌套的组件,这个组件里既要包含已发布的评论内容,又要包含发布新评论的表单。因此,我们评论系统的结构如下图所示:
在这里插入图片描述
在图中,每个Comment都包含两部分:其下的子评论以及发表评论的表单。因此,我们的评论系统要由两个组件组成:其一为显示子评论的list,其二为发布评论的表单。显示子评论的List会以递归的方式从后端获取到该评论下的所有子评论,包括孙子评论;而发布评论的表单功能比较单一,只是一个普通的表单。这样,我们将这两个组件组合起来,便可以实现我们的评论树功能。
在这期博客中,我们实现了故事列表功能,并为大家介绍了评论系统的结构。在下一篇博客中,将继续带领大家开发评论系统,并介绍angular中模板的相关知识,希望大家继续关注~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值