File
Implements
Metadata
| selector |
stbui-chat-widget |
| styleUrls |
./chat-widget.component.scss |
| templateUrl |
./chat-widget.component.html |
Methods
|
addMessage
|
addMessage(from, text, type: "received" | "sent")
|
|
|
Parameters :
| Name |
Type |
Optional |
| from |
|
No
|
| text |
|
No
|
| type |
"received" | "sent"
|
No
|
|
|
clearMessage
|
clearMessage()
|
|
|
|
|
|
focusMessage
|
focusMessage()
|
|
|
|
|
|
randomMessage
|
randomMessage()
|
|
|
|
|
|
scrollToBottom
|
scrollToBottom()
|
|
|
|
|
|
sendMessage
|
sendMessage(undefined)
|
|
|
|
|
|
bottom
|
Type : ElementRef
|
Decorators :
@ViewChild('bottom', {static: false})
|
|
|
|
client
|
Type : object
|
Default value : {
name: '访客',
status: 'online',
avatar: `https://randomuser.me/api/portraits/men/${rand(100)}.jpg`
}
|
|
|
|
message
|
Type : ElementRef
|
Decorators :
@ViewChild('message', {static: false})
|
|
|
|
messages
|
Type : []
|
Default value : []
|
|
|
|
operator
|
Type : object
|
Default value : {
name: 'Stbui',
status: 'online',
avatar: `https://randomuser.me/api/portraits/women/${rand(100)}.jpg`
}
|
|
|
|
visible
|
Default value : false
|
|
|
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
const randomMessages = [
'没事的时候,打打工,不为赚钱,只为锻炼自己。',
'今天天气不错,欢迎新人来到。',
'你匿了那么久,现在终于入群了。',
'亲,欢迎您的再次关注,有什么需要我的帮助吗?很乐意为你效劳!',
'对不起,您的要求不在我们的服务范围内',
'很抱歉,我无法帮助您!',
'您的问题我需要核实一下,请您稍等。',
'请问还有什么可以帮您?',
'感谢您的咨询,再见!',
'请问还有什么可以帮助您?',
'您的问题我已记录好,会提交给相关人员处理,并在三个工作日内回复您。',
':)'
];
const rand = max => Math.floor(Math.random() * max);
const getRandomMessage = () => randomMessages[rand(randomMessages.length)];
@Component({
selector: 'stbui-chat-widget',
templateUrl: './chat-widget.component.html',
styleUrls: ['./chat-widget.component.scss']
})
export class ChatWidgetComponent implements OnInit {
@ViewChild('message', { static: false }) message: ElementRef;
@ViewChild('bottom', { static: false }) bottom: ElementRef;
visible = false;
operator = {
name: 'Stbui',
status: 'online',
avatar: `https://randomuser.me/api/portraits/women/${rand(100)}.jpg`
};
client = {
name: '访客',
status: 'online',
avatar: `https://randomuser.me/api/portraits/men/${rand(100)}.jpg`
};
messages = [];
constructor() { }
ngOnInit() {
setTimeout(() => {
this.addMessage(
this.operator,
'您好,欢迎光临,很高兴为您服务!',
'received'
);
}, 1500);
}
addMessage(from, text, type: 'received' | 'sent') {
this.messages.unshift({
from,
text,
type,
date: new Date().getTime()
});
this.scrollToBottom();
}
scrollToBottom() {
if (this.bottom !== undefined) {
this.bottom.nativeElement.scrollIntoView();
}
}
randomMessage() {
this.addMessage(this.operator, getRandomMessage(), 'received');
}
sendMessage({ message }) {
if (message.trim() === '') {
return;
}
this.addMessage(this.client, message, 'sent');
setTimeout(() => this.randomMessage(), 1000);
}
toggleChat() {
this.visible = !this.visible;
}
onSubmit() {
const message = this.getMessage();
if (message.trim() === '') {
return;
}
this.sendMessage({ message });
this.clearMessage();
this.focusMessage();
}
getMessage() {
return this.message.nativeElement.value;
}
focusMessage() {
this.message.nativeElement.focus();
}
clearMessage() {
this.message.nativeElement.value = '';
}
}
<div class="wrapper">
<div class="chat-box" *ngIf="visible">
<div class="chat-box-header">
<div class="">
<div class="operator-status">
{{operator.status}}
<span class="operator-status-online">●</span>
<button class="chat-button-header" (click)="toggleChat()">✕</button>
</div>
<img [attr.src]="operator.avatar" class="avatar" />
<h3 class="operator-name">
{{operator.name}}
</h3>
</div>
</div>
<div class="chat-box-main">
<div class="chat-message-bottom" #bottom></div>
<ng-container *ngFor="let message of messages">
<div class="chat-message" [class.chat-message-received]="message.type === 'received'" [class.chat-message-sent]="message.type === 'sent'">
<div class="chat-message-row">
<div class="chat-message-from-avatar">
<img [attr.src]="message.from.avatar" class="avatar" />
</div>
<div class="chat-message-text">
{{message.text}}
</div>
</div>
<div class="chat-message-date">
{{message.date | date: 'short'}}
</div>
</div>
</ng-container>
</div>
<div class="chat-box-footer">
<textarea type="text" class="chat-input-text" placeholder="请输入..." #message (keydown.enter)="onSubmit()" (keyup.enter)="message.value = ''"
(keyup.escape)="dismiss.emit()"></textarea>
<button type="submit" class="chat-input-submit" (click)="onSubmit()">↩︎</button>
</div>
</div>
<button mat-fab class="chat-button" (click)="toggleChat()">
<span *ngIf="visible">✕</span>
<span *ngIf="!visible">?</span>
</button>
</div>
.wrapper {
position: absolute;
top: 0;
bottom: 0;
width: 100vw;
}
.chat-button {
z-index: 1;
position: absolute;
bottom: 20px;
right: 40px;
font-size: 32px;
}
.chat-button-header {
z-index: 1;
font-weight: bold;
color: #fff;
border: 1px solid #fff;
background-color: inherit;
padding: 5px 9px;
margin-left: 5px;
}
.chat-box {
z-index: 2;
position: absolute;
left: 0;
height: 100vh;
width: 100vw;
margin: 0;
display: flex;
flex-direction: column;
box-shadow: 0 5px 40px rgba(0, 0, 0, 0.16);
}
.chat-box-hidden {
display: none;
}
.chat-box-header {
padding: 10px;
color: #fff;
}
.chat-box-main {
flex: 1;
width: 100%;
background: #f5f5f5;
display: flex;
flex-direction: column-reverse;
overflow: auto;
}
.chat-box-footer {
color: #fff;
height: 50px;
}
.operator-name {
margin: 0;
padding: 1px;
}
.operator-status {
float: right;
padding: 4px;
}
.operator-status span {
margin-left: 4px;
}
.operator-status-online {
color: lawngreen;
}
.operator-status-offline {
color: red;
}
.operator-avatar {
height: 30px;
width: 30px;
border-radius: 50%;
float: left;
margin-right: 10px;
}
.chat-message {
display: block;
width: auto;
margin: 5px;
align-self: flex-start;
flex-direction: row;
max-width: 80%;
word-wrap: break-word;
}
.chat-message-date {
font-size: 11px;
color: #8d898d;
padding: 5px;
}
.chat-message-row {
position: relative;
}
.chat-message-from-avatar {
height: 35px;
width: 35px;
border-radius: 50%;
}
.chat-message-text {
margin-left: 10px;
padding: 10px;
border-radius: 3px;
position: relative;
}
.chat-message-received {
margin-right: 50px;
}
.chat-message-received .chat-message-text {
background: #b9d6f2;
margin-left: 50px;
border-bottom-left-radius: 0;
}
.chat-message-received .chat-message-text:before {
position: absolute;
content: ' ';
left: -10px;
bottom: 0;
border-right: solid 10px #b9d6f2;
border-top: solid 10px transparent;
z-index: 0;
}
.chat-message-received .chat-message-date {
margin-left: 50px;
}
.chat-message-received .chat-message-from-avatar {
position: absolute;
left: 0;
bottom: -15px;
}
.chat-message-sent {
align-self: flex-end;
}
.chat-message-sent .chat-message-from {
float: right;
}
.chat-message-sent .chat-message-text {
background: #84dccf;
margin-right: 50px;
border-bottom-right-radius: 0;
}
.chat-message-sent .chat-message-text:after {
position: absolute;
content: ' ';
right: -10px;
bottom: 0;
border-left: solid 10px #84dccf;
border-top: solid 10px transparent;
z-index: 0;
}
.chat-message-sent .chat-message-date {
text-align: right;
padding-right: 50px;
}
.chat-message-sent .chat-message-from-avatar {
position: absolute;
right: 0;
bottom: -15px;
}
.blue .chat-button {
background: #1976d2;
}
.blue .chat-box {
background: #1976d2;
}
.grey .chat-button {
background: #454549;
}
.grey .chat-box {
background: #454549;
}
.red .chat-button {
background: #dd0031;
}
.red .chat-box {
background: #dd0031;
}
@media (min-width: 576px) {
.wrapper {
top: auto;
right: 0;
width: 300px;
}
.chat-button {
display: block;
}
.chat-button-header {
display: none;
}
.chat-box {
top: auto;
left: auto;
bottom: 100px;
right: 40px;
height: 60vh;
width: 300px;
border-radius: 10px;
}
}
@media (min-width: 768px) {
.chat-box {
height: 70vh;
}
}
@media (min-width: 992px) {
.chat-box {
height: 80vh;
}
}
@media (min-width: 1200px) {
.chat-box {
/*height: 80vh;*/
}
}
.avatar {
height: 30px;
width: 30px;
border-radius: 50%;
float: left;
margin-right: 10px;
}
.chat-input-text {
margin: 14px 0 0 14px;
height: 25px;
width: 70%;
border: 0;
resize: none;
border: none;
overflow: auto;
outline: none;
box-shadow: none;
font-size: 14px;
background-color: inherit;
color: inherit;
}
.chat-input-text::-webkit-input-placeholder {
color: inherit;
}
.chat-input-text::-moz-placeholder {
color: inherit;
}
.chat-input-text::-ms-input-placeholder {
color: inherit;
}
.chat-input-submit {
margin: 14px 12px;
float: right;
background-color: inherit;
color: inherit;
font-size: 24px;
border: 0;
outline: none;
}
Legend
Html element with directive