第一步  按照即时通讯IM文档来安装

第二步 在main.js  引入

 第三步  找一个空页面粘贴过去就可以了

具体效果图:

业务逻辑代码如下:  

<template>
    <div class="box" v-loading="loading">
      <div class="t_left">

        <div class="seek">
          <el-input
            placeholder="请输入用户名进行搜索"
            v-model="lookup"
            @change = "cLookup"
            clearable>
          </el-input>

        </div>

        <div class="t_left_bot" v-if="rListOff">

          <div v-for="(item,index) in rList" :key="index"
               @click="setZi(item.conversationID,item.userProfile.userID,item.userProfile.avatar,item.userProfile.nick)"
               :class="{ active:item.conversationID==isActive }"
          >
            <img :src="item.userProfile.avatar || defaultAvatar" style="background: #c1c1c1;"/>
            <div>{{item.userProfile.nick || item.userProfile.userID}}</div>
            <div v-show="item.lastMessage">{{item.lastMessage.messageForShow}}</div>
            <div>{{item.lastMessage.lastTime | offTime}}</div>
            <div v-if="item.unreadCount != 0"> {{item.unreadCount > 99 ? '99+' : item.unreadCount}}</div>
          </div>
        </div>
      </div>
      <div class="t_right" v-if="rRightOff">
        <!--名字-->
        <div class="t_right_top">{{chatName}}</div>
        <!--内容-->
        <div class="t_right_con" id="t_right_con">
          <div v-if="hList.isCompleted" class="t_r_nmore">没有更多了</div>
          <div v-else class="t_r_more" @click="seeMore()">查看更多</div>
          <div v-if="hList" >
            <div class="hList-left" v-for="(item,index) in hList.messageList"    :key="index">
              <!--他人发送的消息-->
              <div class="hList-left-a"  v-if="item.to != toUserId">
                <img class="hlAva" :src="avatar || defaultAvatar"/>
                <div>
                   <!-- 判断消息是否是图片 -->
                  <div v-if="item.type == 'TIMImageElem'" v-html="newImg(item)"></div>
                   <!-- 判断消息是否是文字或者表情 -->
                  <div v-if="item.type == 'TIMTextElem'" v-html="emj(item.payload.text)"></div>
                  <!-- 消息时间 -->
                  <div>{{item.time | offTime}}</div>
                </div>
              </div>
              <!--我自己发送的消息-->
              <div class="hList-left-b" v-else>
                <div>
                  <!-- 判断消息是否是图片 -->
                  <div v-if="item.type == 'TIMImageElem'" v-html="newImg(item)"></div>
                   <!-- 判断消息是否是文字或者表情 -->
                  <div v-if="item.type == 'TIMTextElem'" v-html="emj(item.payload.text)"></div>
                  <!-- 消息时间 -->
                  <div>{{item.time | offTime}}</div>
                </div>
                <img class="hlAva" :src="myAvatar"/>
              </div>
            </div>
          </div>
        </div>

        <!--输出框-->
        <div class="t_right_bot">
          <div>
            <!-- 发送图片 -->
            <div class="icture">
              <i class="el-icon-picture"></i>
              <input @change="getFile" id="imagePicker"  ref="imagePicker" accept="image/gif,image/jpeg,image/jpg,image/png,image/svg" type="file"/>
            </div>
            <!-- 发送表情 -->
            <div class="icture_a">
              <el-popover
                ref="popover4"
                placement="top"
                width="400"
                height='160'
                trigger="click">
                <div style="height: 160px; overflow: auto;">
                    <img style="width:30px; cursor: pointer; margin:1px 2px 3px 4px;" v-for="(item,index) in emojiMap" @click="setEmj(item)" :key="index" :src="emojiUrl+item"/>
                </div>
                <div slot="reference">
                  <svg t="1593314000110" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1249" width="28" height="28"><path d="M909.8 305.6c-5.4-10.5-16.3-17.8-28.9-17.8-17.8 0-32.2 14.4-32.2 32.1 0 6 1.7 11.7 4.6 16.5l-0.1 0.1c26.9 52.4 42.1 111.8 42.1 174.7 0 211.6-171.6 383.2-383.2 383.2S128.8 722.9 128.8 511.2 300.4 128.1 512 128.1c62.5 0 121.5 15 173.6 41.5l0.2-0.4c4.6 2.6 10 4.1 15.7 4.1 17.8 0 32.2-14.4 32.2-32.1 0-13.1-7.9-24.4-19.3-29.4C653.6 81 584.9 63.6 512 63.6 264.7 63.6 64.2 264 64.2 511.2S264.7 958.9 512 958.9s447.7-200.4 447.7-447.7c0-74.1-18-144-49.9-205.6z" fill="#4D4D4D" p-id="1250"></path><path d="M771.7 219.7a32.2 32.1 0 1 0 64.4 0 32.2 32.1 0 1 0-64.4 0Z" fill="#4D4D4D" p-id="1251"></path><path d="M368.1 383.8m-45.1 0a45.1 45.1 0 1 0 90.2 0 45.1 45.1 0 1 0-90.2 0Z" fill="#4D4D4D" p-id="1252"></path><path d="M654.2 383.8m-45.1 0a45.1 45.1 0 1 0 90.2 0 45.1 45.1 0 1 0-90.2 0Z" fill="#4D4D4D" p-id="1253"></path><path d="M512.5 739.2c75.7 0 141.2-43.9 172.5-107.6 2.3-4.7 3.8-10 3.8-15.6 0-17.7-14.4-32-32.2-32.1-12.9 0-24.1 7.3-29.2 18.1-20.3 43.5-64.4 73.6-115.4 73.6s-94.4-30.2-114.8-73.5c0-0.1-0.1-0.2-0.1-0.3-5.3-10.6-16.2-17.9-28.9-17.9-17.8 0-32.2 14.4-32.2 32.1 0 5 1.2 9.8 3.3 14.1 30.9 64.5 96.8 109.1 173.2 109.1z" fill="#4D4D4D" p-id="1254"></path></svg>
                </div>
              </el-popover>
            </div>
          </div>
          <div>
            <textarea
              placeholder="请输入内容"
              v-model="textarea"
              maxlength="200"
              @keydown="messageSendlisten"
            >
            </textarea>
            <div class="t_limit">当前还可发送{{200-(textarea.length)}}个字</div>
            <el-button class="r_i" @click="setButton" type="primary">发送</el-button>
          </div>
        </div>
      </div>
    </div>
</template>

<script>
  import {emojiMap,emojiUrl} from '../../../assets/emj'
  export default {
    name: '',
    data(){
      return{
        defaultAvatar:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1651318081,2860235060&fm=26&gp=0.jpg",//默认头像,如果用户没有上传头像或者头像路径错误展示这个路径
        myAvatar:"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2519824424,1132423651&fm=26&gp=0.jpg",//我的头像
        chatName:'',//查看的某个人name
        toUserId:'',//查看的某个人id
        avatar:'',//查看的某个人avatar
        lookup:"",//用户查找的名字
        isActive:'1',
        loading:false,//加载中
        textarea:"",//输入信息
        rListOff:false,
        rRightOff:false,
        emojiMap:emojiMap,
        emojiUrl:emojiUrl,
        rList:[],//会话列表
        hList:[]//具体信息
      }
    },
    filters: {
      //接收时间
      offTime: function(value) {
        var v = value
        var date = new Date(v*1000)
        var Y = date.getFullYear() + '-'
        var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 ) + '-'
        var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate())
        var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
        var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes())
        let dt = new Date(Date.parse(new Date()))
        let current = dt.getFullYear() +"-"+dt.getMonth()+"-"+dt.getDate()
        let system = date.getFullYear() +"-"+date.getMonth()+"-"+date.getDate()
        if(current == system){return h + m} else {return Y+M+D}
      }
    },
    methods:{
      //消息查看更多
      seeMore(){
          const self = this 
          let nextReqMessageID = self.hList.nextReqMessageID
          let promise = tim.getMessageList({conversationID:self.hList.messageList[0].conversationID, nextReqMessageID, count: 15});
          promise.then(function(imResponse) {
              self.hList.messageList = [...imResponse.data.messageList,...self.hList.messageList]
              self.hList.nextReqMessageID = imResponse.data.nextReqMessageID; // 分页
              self.hList.isCompleted = imResponse.data.isCompleted; // 是否已经拉完
              if(self.hList) self.rRightOff = true
          });
      },
      //发送表情
      setEmj(val){
        let obj = this.emojiMap
        let findKey = (value, compare = (a, b) => a === b) =>{
          return Object.keys(obj).find(k => compare(obj[k], value))
        }
        this.$refs.popover4.showPopper = false;
        this.textarea = this.textarea.concat(findKey(val))
      },
      //接收表情判断
      emj(value) {
        let emImg
        for(let key in emojiMap){
          emImg = emojiUrl+emojiMap[key]
          while(value.indexOf(key) != '-1'){
            value = value.replace(key,`<img style='width:25px;' src=${emImg}>`)
          }
        }
         return value
      },
      //查找用户 模糊查找
      cLookup(){
        const self = this
        let promise = this.tim.getConversationList();
        promise.then(function(imResponse) {
          self.rList = imResponse.data.conversationList
          self.rListOff = true
          let arr = []
          if(self.lookup.split(" ").join("").length==0){
            //业务逻辑
            //........
          } else {
            self.rList.map(item=>{
              if(item.userProfile.nick.indexOf(self.lookup)!=-1 || item.userProfile.userID.indexOf(self.lookup)!=-1 ){
                arr.push(item)
              }
            })
          }
          arr.length == 0 ? self.hlData() : self.rList = arr

        }).catch(function(imError) {
          console.log(imError)
          // console.warn('getConversationList error:', imError); // 获取会话列表失败的相关信息
        });
      },
      //图片上传
      getFile(e){
        const self = this
        // 1. 创建消息实例
        self.loading = true
        let message = this.tim.createImageMessage({
          to: self.toUserId,
          conversationType: this.TIM.TYPES.CONV_C2C,
          payload: {
            file: document.getElementById('imagePicker')
          },
          onProgress: function(event) { console.log('file uploading:', event) }
        });
        // 2. 发送消息
        let promise = this.tim.sendMessage(message);
        promise.then(function(imResponse) {
          // 发送成功
          self.textarea = ''
          self.hList.messageList.push(imResponse.data.message)
          self.below()
          self.loading = false
        }).catch(function(imError) {
          console.warn('sendMessage error:', imError);
          self.loading = false
        });

      },
      //自动保持在最底部
      below(){
        this.$nextTick(() => {
          let container = this.$el.querySelector("#t_right_con");
          container.scrollTop = container.scrollHeight;
        })
      },
       //图片初始化
      newImg(val){
          let w = val.payload.imageInfoArray[0].width
          let h = val.payload.imageInfoArray[0].height
          if(w>300){ h = h/(w/300);w = 300}
          return `<img style='width:${w}px;height:${h}px;' src='${val.payload.imageInfoArray[0].imageUrl}'/>`
      },
      //回车发送文本 阻止浏览器默认换行操作
      messageSendlisten(event){
        if (event.keyCode === 13) {
          this.setButton(); // 发送文本
          event.preventDefault(); // 阻止浏览器默认换行操作
          return false;
        }
      },
      //消息已读
      read(id){
        let promise = this.tim.setMessageRead({conversationID: id});
        promise.then(function(imResponse) {
          // 已读上报成功,指定 ID 的会话的 unreadCount 属性值被置为0
        }).catch(function(imError) {
          // 已读上报失败
          console.warn('setMessageRead error:', imError);
        });
      },
      //发送消息
      setButton(){
        const self = this
        if(self.textarea.split(" ").join("").length==0) return this.$message({
          message: '请输入正确信息',
          type: 'warning'
        });
        let message = this.tim.createTextMessage({
          to: self.hList.userID,
          conversationType: this.TIM.TYPES.CONV_C2C,
          payload: {
            text: self.textarea
          }
        });
       // 发送消息
        let promise = tim.sendMessage(message);
        promise.then(function(imResponse) {
          // 发送成功
          self.textarea = ''
          self.hList.messageList.push(imResponse.data.message)
          self.below()

        }).catch(function(imError) {
          // 发送失败
          console.warn('sendMessage error:', imError);
        });
      },
      //获取会话资料
      setZi(conversationID,userID,avatar,chatName){
        const self = this
        if(userID == self.toUserId) {
          return
        } else {
          self.hList = []
        }
        self.toUserId = userID
        self.avatar = avatar
        self.isActive = conversationID
        self.chatName = chatName || userID
        let promise = this.tim.getMessageList({conversationID: conversationID, count: 15});
        promise.then(function(imResponse) {
          let hList = {}
          hList.messageList = imResponse.data.messageList; // 消息列表。
          hList.nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。
          hList.isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。
          hList.userID = userID; // 点击进去的用户id。
          hList.conversationID = conversationID; 
          self.hList = hList
          if(self.hList) self.rRightOff = true
          self.below()
          //设置消息已读
          self.read(conversationID)
        });

      },
      //获取会话列表
      hlData(){
        const self = this
        let promise = this.tim.getConversationList();
        promise.then(function(imResponse) {
          self.rList = imResponse.data.conversationList
          self.rListOff = true
        }).catch(function(imError) {
          console.log(imError)
        });
      },
      logData(userID,userSig){
        const self = this
        let promise = this.tim.login({userID: userID, userSig: userSig});
        promise.then(function(imResponse) {
          //获取会话列表
          if (imResponse.data.repeatLogin === true) {
            // 标识账号已登录,本次登录操作为重复登录。v2.5.1 起支持
            console.log(imResponse.data.errorInfo);
          }
        }).catch(function(imError) {
          console.warn('login error:', imError); // 登录失败的相关信息
        });

        // 监听事件
        this.tim.on(this.TIM.EVENT.SDK_READY, function(event) {
          // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
          self.hlData()
        });

        this.tim.on(this.TIM.EVENT.MESSAGE_RECEIVED, function(event) {
          // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
          self.hlData()
          if(self.hList){
            if(event.data[0].from == self.hList.userID){
              // console.log('这是正在聊天的聊天界面')
              // console.log(event.data[0].conversationID)
              self.read(event.data[0].conversationID)
              self.hList.messageList.push(event.data[0])
              self.below()
            }
          }
        });
      },
    },
    created () {
        const self = this
        let userID = 'yaohuiqian'
        let userSig = 'eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zLBwpWJ*RmlmYWZiXlQ2eKU7MSCgswUJStDEwMDYwsLM2MLiExqRUFmUSpQ3NTU1MjAwAAiWpKZCxazNAIqtTQzg5qSmQ403M033bzQ2NPFxMvXCWhahXtUWkqwZaJXUFhAhoeBuba2e0Gih3eQibGPo61SLQBhhTHK'
        self.logData(userID,userSig)

    },
    destroyed() {
      // 离开页面退出当前账号
      let promise = this.tim.logout();
      promise.then(function(imResponse) {
        console.log(imResponse.data); 
      }).catch(function(imError) {
        console.warn('logout error:', imError);
      });
    }
  }
</script>

<style scoped lang="scss">
  @mixin toCla {
    color: #a5b5c1;
    font-size: 12px;
  }
  @mixin toClb {
    display: inline-block;
    >div:nth-child(1):before{
      content: "";
      width: 0px;
      height: 0px;
      border-top: 7px solid transparent;
      border-bottom: 7px solid transparent;

      position: absolute;
      top: 10px;
      font-size: 7px;
    }
    >div:nth-child(2){
      color: #a5b5c1;
      font-size: 12px;
      margin-top: 9px;
    }
    >div:nth-child(1){
      outline: none;
      font-size: 14px;
      position: relative;
      max-width: 350px;
      word-wrap: break-word;
      word-break: break-all;
      background: #FFF;
      border-radius: 5px;
      display: inline-block;
      padding: 10px;
      -webkit-box-shadow: 0 5px 10px 0 rgba(0,0,0,0.1);
      box-shadow: 0 5px 10px 0 rgba(0,0,0,0.1);
      margin-top: 20px;
    }
  }
.box{
  width: 90%;
  height: 90%;
  margin: 0 auto;
  margin-top: 2%;
  display: flex;
  -moz-box-shadow:2px 2px 5px #333333;
  -webkit-box-shadow:2px 2px 5px #333333;
  box-shadow:2px 2px 5px #333333;
  position: relative;
  .t_left{
    width: 260px;
    height: 600px;
    overflow: auto;
    border-right: 1px solid #e5e5e5;
    .seek{
      overflow: hidden;
      background: red;
      position: absolute;
      width: 256px;
      z-index: 9;
      top: 0;
      left: 0;
      /deep/.el-input__inner{
        height: 35px;
        border: 0 !important;
        border-radius: 0 !important;
        border-bottom: 1px solid #b2b2b2 !important;
      }
    }
    .t_left_bot{
      padding-top: 36px;
      overflow: auto;
      >div{
        width: 100%;
        height: 80px;
        background: #FFF;
        border-bottom: 1px solid #e5e5e5;
        cursor: pointer;
        position: relative;
        div:nth-child(5){
          position: absolute;
          width: 18px;
          height: 18px;
          line-height: 18px;
          text-align: center;
          font-size: 11px;
          top: 4px;
          left: 58px;
          color: #FFF;
          background: red;
          border-radius: 50%;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
        div:nth-child(4){
          position: absolute;
          width: 80px;
          font-size: 14px;
          top: 15px;
          left: 169px;
          color: #b2b2b2;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          text-align: right;
        }
        div:nth-child(3){
          position: absolute;
          width: 163px;
          font-size: 14px;
          top: 45px;
          left: 83px;
          color: #b2b2b2;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
        div:nth-child(2){
          position: absolute;
          width: 90px;
          font-size: 16px;
          top: 13px;
          left: 83px;
          overflow: hidden;
          text-overflow:ellipsis;
          white-space: nowrap;
        }
        img{
          width: 60px;
          height: 60px;
          position: absolute;
          top: 10px;
          left: 10px;
          border-radius: 2px;
        }
      }
    }
  }
  .t_right{
    flex: 1;
    background: #f3f3f3;

    .t_right_bot{
      border-top: 1px solid #e5e5e5;
      height: 139px;
      width: 100%;
      background: #FFF;
      position: relative;
      /deep/.t_limit{
        position: absolute;
        right: 93px;
        bottom: 17px;
        color: #b2b2b2;
      }
      /deep/textarea{
        resize: none;
        height: 100px;
        border: 0;
        width: 96%;
        display: block;
        margin: 0 auto;
        outline: none;
      }
      .r_i{
        position: absolute;
        right: 12px;
        bottom: 7px;
        color: #FFF;
      }
      >div:nth-child(1){
        display: flex;
        align-items: center;
        .icture_a{
            display: inline-block;
            cursor: pointer;
            position: relative;
            margin-left: 5px;
   
            /deep/.el-popover{
              width: 400px !important;
              height: 160px !important;
              overflow: auto !important;
            }
        }
        .icture{
          width: 30px;
          height: 30px;
          display: inline-block;
          margin: 4px 15px;
          cursor: pointer;
          overflow: hidden;
          position: relative;
        }
        input[type="file"] {
          color: transparent;
        }
        input{
          cursor: pointer !important;
          position: absolute;
          top: 0;
          left: 0;
          width: 30px;
          height: 30px;
          opacity: 0;
        }
        /deep/i{
          font-size: 27px;

        }
      }
    }
    .t_right_con{
      height: 410px;
      overflow: auto;
      .t_r_nmore{
         display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            justify-content: center;
            font-size: 13px;
            color: #a5b5c1;
            background: 0 0;
            padding-left: 0;
            padding-right: 0;
            cursor: pointer;
      }
      .t_r_more{
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            justify-content: center;
            font-size: 13px;
            color: #409EFF;
            background: 0 0;
            padding-left: 0;
            padding-right: 0;
            cursor: pointer;
      }
    }


    .t_right_top{
      padding: 0 20px;
      color: #1c2438;
      font-size: 18px;
      font-weight: bold;
      line-height: 50px;
      text-shadow: #76828c 0 0 0.1em;
    }
    .hList-left{
      width: 100%;
      position: relative;
      overflow: auto;
      .hlAva{
        width: 56px;
        height: 56px;
        border-radius: 50%;
        display: block;
        display: inline-block;
        margin: 10px 20px;
        vertical-align: top;
      }
      .hList-left-b{
        text-align: right;
        >div:nth-child(2){
          @include toCla;
        }
        >div:nth-child(1){
          @include toClb;
          >div:nth-child(1):before{
            border-top: 7px solid transparent !important;
            border-bottom: 7px solid transparent !important;
            border-left: 7px solid #FFF !important;
            right: -7px !important;
          }
        }
       }
      .hList-left-a{
        >div:nth-child(3){
          @include toCla;
        }
        >div:nth-child(2){
          @include toClb;
          >div:nth-child(1):before{
            left: -7px !important;
            border-right: 7px solid #FFF !important;
          }
        }

      }

    }

  }
  .active{
    transition: 300ms;
    background: #d6d6d6 !important;
  }

}

  /* 设置滚动条的样式 */
  ::-webkit-scrollbar {
    width: 3px;
    height: 3px;
  }

  /* 滚动槽 */
  ::-webkit-scrollbar-track {
    border-radius: 10px;
  }

  /* 滚动条滑块 */
  ::-webkit-scrollbar-thumb {
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.1);
  }

</style>

 

Logo

前往低代码交流专区

更多推荐