vue 웹 온라인 채 팅 기능 구현

12476 단어 vue잡담 하 다
본 논문 의 사례 는 vue 가 웹 온라인 채 팅 을 실현 하 는 구체 적 인 코드 를 공유 하여 여러분 께 참고 하 시기 바 랍 니 다.구체 적 인 내용 은 다음 과 같 습 니 다.
최종 실현 의 효과

실현 과정
무한 스크롤 창 이 실현 되 기 전에 소 개 했 습 니 다.여 기 는 군말 이 아 닙 니 다.잘 모 르 는 것 은 문서 앞의 전송 문 을 통 해 볼 수 있 습 니 다.
실시 간 온라인 채 팅 주요 기능 점
4.567917.이틀 창 상단 으로 스크롤 하여 역사 와 다 중 정 보 를 자동 으로 불 러 옵 니 다.데 이 터 를 불 러 올 때 loading 애니메이션 이 필요 합 니 다4.567917.메 시 지 를 보 내 는 것 은 스크롤 바 가 자동 으로 창 아래로 미 끄 러 지고 자신 이 보 낸 메 시 지 는 채 팅 창 에 나타 납 니 다4.567917.다른 사람 이 메 시 지 를 보 낼 때 스크롤 바 가 창문 에 있 는 위 치 를 판단 하고 바닥 에서 일정한 범위 내 에서 정 보 를 받 으 려 면 자동 으로 창문 아래로 미끄러져 야 한다
  • 받 은 메 시 지 는 채 팅 상태 에서 중복 표시 할 수 없습니다
  • 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>
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기