vue 웹 온라인 채 팅 기능 구현
최종 실현 의 효과
실현 과정
무한 스크롤 창 이 실현 되 기 전에 소 개 했 습 니 다.여 기 는 군말 이 아 닙 니 다.잘 모 르 는 것 은 문서 앞의 전송 문 을 통 해 볼 수 있 습 니 다.
실시 간 온라인 채 팅 주요 기능 점
4.567917.이틀 창 상단 으로 스크롤 하여 역사 와 다 중 정 보 를 자동 으로 불 러 옵 니 다.데 이 터 를 불 러 올 때 loading 애니메이션 이 필요 합 니 다4.567917.메 시 지 를 보 내 는 것 은 스크롤 바 가 자동 으로 창 아래로 미 끄 러 지고 자신 이 보 낸 메 시 지 는 채 팅 창 에 나타 납 니 다4.567917.다른 사람 이 메 시 지 를 보 낼 때 스크롤 바 가 창문 에 있 는 위 치 를 판단 하고 바닥 에서 일정한 범위 내 에서 정 보 를 받 으 려 면 자동 으로 창문 아래로 미끄러져 야 한다
말 이 많 지 않 으 면,직접 코드 를 붙인다.
백 엔 드 반환 데이터 형식
나 는 모든 디자인 과 기능 실현 이 데이터 에 기초 하여 이 루어 진 것 이 라 고 생각한다.그래서 어떻게 하면 백 엔 드 에서 돌아 오 는 데이터 형식 을 먼저 볼 수 있 을 까?
{
"code": 200, //
"msg": "OK", //
"total": 1,
"sysTime": "2020-12-16 15:23:27", //
"data": [{
"avatar": "", //
"content": "{\"type\":\"txt\",\"msg\":\" !\"}", //
"isRead": 0, //
"isOneself": 0, // 0 ,1
"msgId": 10, // ID,
"nickName": " ", //
"userCode": "202012162030202232" //
}]
}
여기 서 설명 할 것 은 content 필드 는 json 형식의 문자열 데 이 터 를 되 돌려 줍 니 다.content 내용 형식 은 다음 과 같 습 니 다.
//
{
"type": "txt",
"msg":" " //
}
//
{
"type": "img",
"url": " ",
"ext":"jpg",
"width":360, //
"height":480, //
"size": 388245
}
//
{
"type": 'video',
"url": "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e",
"ext":"mp4",
"width":360, //
"height":480, //
"size": 388245
}
//
{
"type": "local",
"address":" 599 ", //
"longitude":120.1908686708565, //
"latitude":30.18704515647036 //
}
HTML 코드
<template>
<Modal title=" " v-model="chatVisible"
draggable
footer-hide
:width="580" @on-cancel="cancel">
<div class="chat">
<div class="chat-message-body" id ="chatform" @scroll="scroll"
>
<Spin v-if="loading">
<Icon type="ios-loading" size=18 class="spin-icon-load"></Icon>
</Spin>
<div dis-hover v-for="(item,index) in data"
:key="index" class="message-card">
<div :class="item.isOneself == 1?'message-row-right': 'message-row-left'">
<img :src="item.avatar?item.avatar:defualtAvatar"
height="35" width="35" >
<div class="message-content">
<div :style="item.isOneself == 1?'text-align:right;display: flex;flex-direction:row-reverse':''">
{{item.nickName}}
<span class="message-time">
{{item.createTime}}</span>
</div>
<div class="message-body">
{{item.content.msg}}
</div>
</div>
</div>
</div>
</div>
<Input
v-model="form.msg"
type="textarea"
style="margin:10px 0;"
placeholder=" , !"
:rows="4"
/>
</div>
<div class="footer-btn">
<Button @click="cancel" type="text"> </Button>
<Button type="primary" @click="sendMsg"> </Button>
</div>
</Modal>
</template>
주:자신 이 보 낸 메 시 지 는 다른 사람 이 보 낸 메시지 와 전시 양식 이 다 르 기 때문에 isOneself 필드 를 통 해 전시 양식 을 구분 해 야 합 니 다.자 바스 크 립 트 코드
<script>
import {listMsg,sendMsg } from "@/api/index";
export default {
name: "chat",
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
chatVisible:this.value,
loading:false,
defualtAvatar:require('../../assets/defult-avatar.svg'), // , : require
data:[],
distincData:[], //
offsetMax:0, // , id, id
offsetMin:0, // , id, id
searchForm:{ // form
pageNumber: 1,
pageSize: 20
},
form:{ //
content:"",
msg:""
},
timerSwitch:0 // ,
};
},
methods: {
init(){
},
loadMsg(){ // ,
let that = this;
this.searchForm.offsetMax = this.offsetMax;
listMsg(this.searchForm).then(res=>{
if (res.code == 200) {
res.data.forEach(e => {
//
if(that.offsetMax < e.msgId){
that.offsetMax = e.msgId;
}
e.content = JSON.parse(e.content);
that.data.unshift(e)
that.distincData.push(e.msgId);
// , , id
that.offsetMin = e.msgId;
});
// ,
this.scrollToBottom();
}
});
},
show(){ //
//
this.data =[];
this.distincData =[];
this.offsetMax = 0;
this.offsetMin = 0;
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.form ={
content:"",
msg:""
};
this.loadMsg();
this.chatVisible = true;
//
this.timerSwitch = 1;
this.reloadData();
},
sendMsg(){ //
if(!this.form.msg){
this.$Message.warning(" ");
return;
}
let content = { //
type:"txt",
msg:this.form.msg
};
this.form.content = JSON.stringify(content);
sendOrderMsg(this.form).then(res=>{
if (res.code == 200) {
res.data.content = JSON.parse(res.data.content);
this.data.push(res.data)
this.form.msg="";
this.distincData.push(res.data.msgId);
this.scrollToBottom();
// , ,
}
});
},
scrollToBottom(){ //
this.$nextTick(()=>{
let chatform = document.getElementById("chatform");
chatform.scrollTop = chatform.scrollHeight;
});
},
// , , 。 ,
scroll(){
let chatform = document.getElementById("chatform");
let scrollTop = chatform.scrollTop;
if(scrollTop == 0){
this.loading =true;
let that = this;
this.searchForm.offsetMin = this.offsetMin;
this.searchForm.offsetMax = "";
listMsgByOrder(this.searchForm).then(res=>{
this.loading =false;
if (res.code == 200) {
res.data.forEach(e => {
if(that.distincData.indexOf(e.msgId) <0){
e.content = JSON.parse(e.content);
that.data.unshift(e);
that.distincData.push(e.msgId);
//
if(that.offsetMin > e.msgId){
that.offsetMin = e.msgId;
}
}
});
}
});
}
},
reloadData(){
// , ,
if(this.timerSwitch){
setTimeout(() => {
let params = {};
params.pageNumber = 1;
params.pageSize = 20;
params.offsetMax = this.offsetMax;
let that = this;
listMsgByOrder(params).then(res=>{
if (res.code == 200) {
res.data.forEach(e => {
// , , ,
if(that.offsetMax < e.msgId){
that.offsetMax = e.msgId;
}
if(that.distincData.indexOf(e.msgId) <0){
e.content = JSON.parse(e.content);
that.data.push(e)
that.distincData.push(e.msgId);
// , , 100,
let chatform = document.getElementById("chatform");
let gap = chatform.scrollHeight -chatform.scrollTop;
if(gap >0 && gap < 400){
this.scrollToBottom();
}
}
});
that.reloadData();
}
});
},1000*2);
}
},
cancel(){ //
this.chatVisible = false;
this.timerSwitch = 0;
}
},
mounted() {
}
};
</script>
CSS 코드
<style lang="less">
.message {
height: 350px;
}
.ivu-card-body {
padding:5px;
}
.ivu-modal-body{
padding: 0px 16px 16px 16px;
}
.chat-message-body {
background-color:#F8F8F6;
width:545px;
height: 350px;
overflow: auto;
}
.message-card {
margin:5px;
}
.message-row-left {
display: flex;
flex-direction:row;
}
.message-row-right {
display: flex;
flex-direction:row-reverse;
}
.message-content {
margin:-5px 5px 5px 5px;
display: flex;
flex-direction:column;
}
.message-body {
border:1px solid #D9DAD9;
padding:5px;
border-radius:3px;
background-color:#FFF;
}
.message-time {
margin:0 5px;
font-size:5px;
color:#D9DAD9;
}
.footer-btn {
float:right;
margin-bottom: 5px;
}
.spin-icon-load {
animation:ani-spin 1s linear infinite;
}
@keyframes ani-spin{
form{transform: rotate(0deg);}
50% {transform: rotate(180deg);}
to {transform: rotate(360deg);}
}
</style>
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Fastapi websocket 및 vue 3(Composition API)1부: FastAPI virtualenv 만들기(선택 사항) FastAPI 및 필요한 모든 것을 다음과 같이 설치하십시오. 생성main.py 파일 및 실행 - 브라우저에서 이 링크 열기http://127.0.0.1:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.