其他分享
首页 > 其他分享> > 向全栈迈进——Angular+Tornado开发树洞博客(十一)

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

作者:互联网

在上一篇博客中,我们开发了评论系统的前端部分,介绍了angular中模板的概念。在这篇博客中,我们将继续开发评论系统的前端部分,并介绍组件间通信的相关内容。
打开comments.component.ts文件,输入以下内容:

//comments.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { CommentService } from 'src/app/service/comment.service';

@Component({
  selector: 'app-comments',
  templateUrl: './comments.component.html',
  styleUrls: ['./comments.component.scss']
})
export class CommentsComponent implements OnInit {
  showComment:boolean[]
  @Input() commentTree:any;
  @Input() storyId:number;

  constructor() {
    this.showComment = [false];
    this.storyId = 0;
   }

  ngOnInit(): void {
  }

  showCommentForm(storyId:number){
    this.showComment[storyId] = !this.showComment[storyId];
  }
}

这个组件中有两个属性:commentTree和storyId,前者用于存放评论树内容,而后者表示当前评论树属于哪个故事。
由于我们这个控件要作为storyList的子控件使用,即需要由storyList指定comments组件要放在哪个故事下面,因此我们使用@Input()修饰器来修饰commentTree和storyId参数,表明storyList组件可以指定comments组件中这两个属性的值:
使用@Input修饰器可以让父组件传递数据给子组件
底下的showCommentForm函数用来反转showComment数组中对应元素的值,控制评论树中评论表单的隐现。
这样,我们这个comments的前端部分就开发完了,下面让我们实现另一个组件commentForm,
这个组件用于让用户发表评论。
打开commentform/commentform.component.html,输入以下代码:

<!--commentform.component.html-->
<form nz-form  [formGroup]="commentForm" (ngSubmit)="publishComment()">
    <nz-form-item>
      <nz-form-control>
          <input formControlName="content" nz-input placeholder="说点什么" />
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-control>
        <button nz-button nzType="primary">发表</button>
      </nz-form-control>
    </nz-form-item>
</form>

这个组件没什么说的,就是一个简单的表单。
下面打开commentform.component.ts文件,输入以下代码:

//commentform.component.ts
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { NzMessageService } from 'ng-zorro-antd/message';
import { CookieService } from 'ngx-cookie-service';
import { CommentService } from 'src/app/service/comment.service';
import { commentData } from '../storylist/commentData';
import { refreshCommentInfo } from './refreshcommentinfo';

@Component({
  selector: 'app-commentform',
  templateUrl: './commentform.component.html',
  styleUrls: ['./commentform.component.scss']
})
export class CommentformComponent implements OnInit {
  newComment:commentData;
  author:string;
  @Input() commentBody:string;
  @Input() storyId:number;
  @Output() refreshCommentEvent: EventEmitter<refreshCommentInfo>;


  commentForm = new FormGroup({
    content:new FormControl('')
  });

  constructor(private cookie:CookieService,private commentService:CommentService,private message:NzMessageService,private router:Router) {
    this.newComment = {
      author:'',
      content:'',
      commentBody:''
    }
    this.author = this.cookie.get('currentuser');
    this.commentBody = ''
    this.storyId = 0
    this.refreshCommentEvent = new EventEmitter();
   }

  ngOnInit(): void {
    console.log('comment form ' + this.commentBody)
    console.log('storyid:' + this.storyId)
  }

  publishComment(){
    this.newComment = this.commentForm.value;
    this.newComment.author = this.author;
    this.newComment.commentBody = this.commentBody;
    this.commentService.writeComment(this.newComment).subscribe((data:any)=>{
      if (data){
        if (data['result'] == 'Success'){
          console.log('Success comment');
          console.log('storyid:' + this.storyId)
          console.log('external storyId:' + this.newComment.commentBody)
          this.message.create('success','评论成功')
          this.commentForm.setValue({'content':''});
          setTimeout(() => {
            this.refreshCommentEvent.emit({'storyId':this.storyId,'externalStoryId':this.newComment.commentBody});
          }, 800);
        }
      }
    })
  }

}

我们来看一下这个组件中用到了哪些变量:

<!--storylist.component.html-->
<div *ngFor="let story of storyList" >
    <nz-card nzTitle="{{story.title}}" >
	<!--...-->
    <span *nzSpaceItem ><i nz-icon nzType="comment" nzTheme="outline"></i><a (click)="showAllComment(story.id,story.externalId)"> 评论</a> </span>
	<!--...-->
    </nz-space>
    </nz-card>
    <div *ngIf="showComment[story.id]">
    <nz-card nzTitle="评论" >
        <app-commentform [commentBody]="story.externalId" [storyId]="story.id" (refreshCommentEvent)="refreshComment($event)"></app-commentform>
        <app-comments [commentTree] = "commentTree" [storyId]="story.id"></app-comments>
    </nz-card>
    </div>
    <br>
</div>

我们为之前的评论标签添加一个a标签,让它调用我们稍后要实现的showAllComment函数来控制评论栏的隐现。这里我们用一个存有storyId的布尔型数组showComment来控制评论栏的隐现,如果对应storyId的值是true,则显示该故事的评论栏以及底下的评论树。
在commentform控件中,我们用**[commentBody][storyId]的语法向commentForm中的同名属性传值,表明评论框的评论是给这个故事的。类似的,我们在comments控件中也会传入[commentTree][storyId]**的属性,以便显示故事的评论树。
我们打开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';
import { CommentService } from 'src/app/service/comment.service';
import { refreshCommentInfo } from '../commentform/refreshcommentinfo';

@Component({
  selector: 'app-storylist',
  templateUrl: './storylist.component.html',
  styleUrls: ['./storylist.component.scss']
})
export class StorylistComponent implements OnInit {
  storyList:storyDetail[];
  showComment:boolean[];
  public commentTree:any;
  commentForm = new FormGroup({
    content:new FormControl('')
  });

  constructor(private storyService:StoryService,private commentService:CommentService) {
  	//...
    this.showComment = [false];
   }
  ngOnInit(): void {

  }
  //...
  showAllComment(storyId:number,externalStoryId:string){
    this.showComment[storyId] = !this.showComment[storyId];
    this.getAllComment(storyId,externalStoryId);
  }
  getAllComment(storyId:number,externalStoryId:string){
    const commentowner = {'storyId':externalStoryId}
    this.commentService.getComment(commentowner).subscribe((data:any) =>{
      console.log(data['result']);
      //this.data = data;
      this.commentTree[storyId] = data['result'];
    })
  }
  refreshComment(info:refreshCommentInfo){
    this.showComment[info['storyId']] = true;
    this.getAllComment(info['storyId'],info['externalStoryId']);
  }
}

这里我们定义了两个新变量:showComment和commentTree,前者用于控制评论栏的隐现,而后者用于显示故事的评论树。在构造函数中,我们将showComment设为false,即在默认情况下不显示评论。
然后,我们实现一个showAllComment函数,这个函数的功能之一是反转showComment数组的指定元素的值,从而实现点击评论按钮来隐藏显示评论栏;功能之二是稍后要实现的获取该故事的评论树getAllComment函数;而refreshComment函数用于用户发表评论后重新获取当前故事的评论。
下面再让我们实现评论的service部分,打开cmd窗口,输入以下命令:

ng g s service/comment

然后打开comment.service.ts文件,输入以下代码:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { commentOwner } from '../story/comments/commentowner';
import { commentData } from '../story/storylist/commentData';

@Injectable({
  providedIn: 'root'
})
export class CommentService {

  constructor(private http:HttpClient) { }

  writeComment(comment:commentData):Observable<commentData>{
    return this.http.post<commentData>('http://localhost:8000/writecomment',comment)
  }

  getComment(storyId:commentOwner):Observable<commentOwner>{
    return this.http.post<commentOwner>('http://localhost:8000/getcomment',storyId)
  }

}

这里我们实现两个service:writeComment和getComment。顾名思义,前者用于发表评论,后者用于获取评论。
这样,我们就完成了评论系统所有的前端开发部分。我们来总结一下在这两篇博客中用到的知识点:

标签:Tornado,component,全栈,评论,showComment,storyId,组件,import,Angular
来源: https://blog.csdn.net/BetrayArmy/article/details/121454091