如何动态使用MDBootstrap Chat组件?
问题:MDBootstrap 5聊天功能需刷新页面才生效(已用SignalR后端)
我在应用中使用MDBootstrap 5的聊天功能,基于官方聊天扩展模板编写了代码,但即便后端用了SignalR,仍必须刷新页面才能让聊天内容更新。
模板代码如下:
<section style="background-color: #eee;"> <div class="container py-5"> <div class="row d-flex justify-content-center"> <div class="col-md-10 col-lg-8 col-xl-6"> <div class="card" id="chat2"> <div class="card-header d-flex justify-content-between align-items-center p-3"> <h5 class="mb-0">Chat</h5> <button type="button" class="btn btn-primary btn-sm" data-mdb-ripple-color="dark"> Let's Chat App </button> </div> <div class="card-body" data-mdb-perfect-scrollbar="true" style="position: relative; height: 400px"> <div *ngFor="let message of (messageService.messageThread$ | async)"> <ng-container *ngIf="message.senderUsername !== currentUser!.userName"> <div class="d-flex flex-row justify-content-start"> <img src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava3-bg.webp" alt="avatar 1" style="width: 45px; height: 100%;"> <div> <p class="small p-2 ms-3 mb-1 rounded-3" style="background-color: #f5f6f7;">ouweee {{message.content}}</p> <p class="small ms-3 mb-3 rounded-3 text-muted">{{message.messageSent | date:'medium'}}</p> <span class="text-danger" *ngIf="!message.dateRead">(unread)</span> <span class="text-success" *ngIf="message.dateRead">(read {{message.dateRead + 'Z' | timeago}})</span> </div> </div> </ng-container> <ng-container *ngIf="message.senderUsername === currentUser!.userName"> <div class="d-flex flex-row justify-content-end mb-4 pt-1"> <div> <p class="small p-2 me-3 mb-1 text-white rounded-3 bg-primary"> Nouwweee {{message.content}}</p> <p class="small me-3 mb-3 rounded-3 text-muted d-flex justify-content-end">{{message.messageSent | date:'medium'}}</p> <span class="text-danger" *ngIf="!message.dateRead">(unread)</span> <span class="text-success" *ngIf="message.dateRead">(read {{message.dateRead + 'Z' | timeago}})</span> </div> <img src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava4-bg.webp" alt="avatar 1" style="width: 45px; height: 100%;"> </div> </ng-container> </div> <form [formGroup]="messageForm" enctype="multipart/form-data" (ngSubmit)="createNewMessage()"> <div class="card-footer text-muted d-flex justify-content-start align-items-center p-3"> <img src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava3-bg.webp" alt="avatar 3" style="width: 40px; height: 100%;"> <input type="text" class="form-control form-control-lg" id="exampleFormControlInput1" placeholder="Type message" formControlName="content" name="content"> <a class="ms-1 text-muted" href="#!"><i class="fas fa-paperclip"></i></a> <a class="ms-3 text-muted" href="#!"><i class="fas fa-smile"></i></a> <button class="btn btn-primary" type="submit">Send</button> </div> </form> </div> </div> </div> </div> </div> </section>
解决方案
1. 修复SignalR数据流推送逻辑
- 确保
messageService.messageThread$基于BehaviorSubject/ReplaySubject实现,且收到SignalR消息时,通过创建新数组触发数据流更新:// messageService.ts import { BehaviorSubject } from 'rxjs'; import { Message } from './your-message-model'; private messageThreadSource = new BehaviorSubject<Message[]>([]); messageThread$ = this.messageThreadSource.asObservable(); // SignalR消息监听逻辑 this.hubConnection.on('ReceiveMessage', (newMessage: Message) => { const currentMessages = this.messageThreadSource.value; // 必须创建新数组,Angular变更检测才能识别变化 this.messageThreadSource.next([...currentMessages, newMessage]); });
2. 触发MDB滚动条自动更新
模板中使用了data-mdb-perfect-scrollbar,新消息加入后需手动滚动到底部:
// 组件中添加滚动方法 scrollToBottom() { const chatContainer = document.querySelector('.card-body[data-mdb-perfect-scrollbar]'); if (chatContainer) { setTimeout(() => { chatContainer.scrollTop = chatContainer.scrollHeight; }, 100); } } // 在收到新消息或发送消息后调用该方法
3. 处理OnPush变更检测(若使用)
如果组件设置了ChangeDetectionStrategy.OnPush,需手动触发变更检测:
import { ChangeDetectorRef } from '@angular/core'; constructor(private cdr: ChangeDetectorRef) {} // 更新数据流后调用 this.cdr.detectChanges();
4. 优化本地消息更新
发送消息时先本地更新数据,无需等待后端推送,提升体验:
async createNewMessage() { if (this.messageForm.valid) { const newMessage = { ...this.messageForm.value, senderUsername: this.currentUser!.userName, messageSent: new Date(), dateRead: null }; // 本地更新消息列表 const currentMessages = this.messageService.messageThreadSource.value; this.messageService.messageThreadSource.next([...currentMessages, newMessage]); // 清空输入框 this.messageForm.reset(); // 发送到后端 await this.hubConnection.invoke('SendMessage', newMessage); // 滚动到底部 this.scrollToBottom(); } }
内容的提问来源于stack exchange,提问作者Jean De La Hone
相关产品推荐
相关产品推荐

