検索
ホームページWeChat アプレットミニプログラム開発ミニプログラムにSDKをインポートしてチャット機能を実装する方法

ミニプログラムにSDKをインポートしてチャット機能を実装する方法

SDK を小さなプログラムにインポートしてチャット機能を実装する方法

最初に npm を使用して Tencent Cloud のインスタント チャット SDK をダウンロードし、次にそれを参照します。プロジェクトを作成し、SDK の初期化を実行し、バックグラウンド インターフェイスの 2 つのパラメーターに基づいて userID と userSig を返し、現在ログインしているユーザーを特定し、最後にドキュメントに従って基本機能を実装します。

#サンプルコード

wxml:

<scroll-view  bindscroll="refresh" scroll-into-view="{{toView}}" style="height: {{scroll_height}}px;" upper-threshold="100" scroll-y="true" enable-back-to-top="true" class="message-list">
  <!-- 每一行 -->
  <view class="row" wx:for="{{messages}}" wx:key="{{index}}" id="row_{{index}}">
    <!-- 日期 -->
    <view class="datetime" wx:if="{{item.msgTime != &#39;&#39;}}">{{item.msgTime}}</view>
    <!-- 头像与内容文本 -->
    <view class="body" style="flex-flow: {{item.flow == &#39;in&#39; ? &#39;row&#39; : &#39;row-reverse&#39;}}">
      <view class="avatar-container">
        <image wx:if="{{item.flow==&#39;in&#39;}}" class="avatar" src="{{friendAvatarUrl}}" />
        <image wx:else class="avatar" src="{{userData.avatarUrl}}" />
      </view>
      <!-- 画对话框 -->
      <view class="triangle" style="{{item.flow == &#39;out&#39; ? &#39;right: 140rpx; background: #7ECB4B&#39; : &#39;left: 140rpx;&#39;}}"></view>
      <view class="content" style="{{item.flow == &#39;out&#39; ? &#39;background: #7ECB4B&#39; : &#39;&#39;}}">
        <view wx:if="{{item.type === &#39;TIMTextElem&#39;}}">{{item.payload.text}}</view>
        <image class="image-message" wx:elif="{{item.type === &#39;TIMImageElem&#39;}}" src="{{item.payload.imageInfoArray[1].url}}" bindtap="previewImage" data-src="{{item.payload.imageInfoArray[1].url}}"></image>
        <view wx:elif="{{item.type === &#39;TIMSoundElem&#39;}}" url="{{item.payload.url}}">
          <view class="box" bindtap="openAudio" data-eventid="{{&#39;13_&#39;+index}}"  data-time="{{item.payload.second}}" data-comkey="{{item.payload.url}}">
            <image  src="{{&#39;13_&#39;+index==audioIndex?audioGif:audioPng}}" style="height:22px;width:22px" class="_image"></image>
            <view style="padding-left: 4px;" class="_div data-v-afeb3abc">
              {{item.payload.second<1?1:item.payload.second}}s
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</scroll-view>
<view class="reply" style="bottom:{{reply_height}}px;">
  <view class="Audio">
    <image wx:if="{{opration==true}}" bindtap="Audio" src="../image/Audio.png"></image>
    <image wx:else bindtap="keyboard" src="../image/keyboard.png"></image>
  </view>
  <view class="opration-area">
    <input bindfocus="bindfocus" wx:if="{{opration==true}}" type="text" bindinput="getContent" value="{{content}}" />
    <view wx:else class="voice-button {{touchBtn?&#39;hoverBtn&#39;:&#39;&#39;}}" bind:touchstart="startAudio" bind:touchend="onTouchEnd" bind:longpress="onLongpress" bind:touchmove="onTouchMove">
      {{touchBtn?&#39;松开 结束&#39;:&#39;按住说话&#39;}}
    </view>
  </view>
  <view class="{{sendBtn==true?&#39;send&#39;:&#39;sendActive&#39;}}" bindtap="sendMsg">发送</view>
  <view class="add" bind:tap="moreClick">
    <image class="more" src="../image/more.png"></image>
  </view>
  <!-- <view class="send" bindtap="sendImg">相册</view>
  <view class="send" bindtap="startAudio">开始</view>
  <view class="send" bindtap="endAudio">结束</view> -->
</view>
<view class="more_box" hidden="{{moreShow}}"> 
  <view class="more_item" bindtap="sendImg">
    <view class="img_box">
      <image src="../image/picture.png"></image>
    </view>
    <view style="margin-top:10rpx;">
      <text>相册</text>
    </view>
  </view>
</view>

js:


import TIM from &#39;tim-wx-sdk&#39;;
import COS from "cos-wx-sdk-v5";
let options = {
  SDKAppID: 0 // 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID
};
// 创建 SDK 实例,`TIM.create()`方法对于同一个 `SDKAppID` 只会返回同一份实例
let tim = TIM.create(options); // SDK 实例通常用 tim 表示
// 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
tim.setLogLevel(1); // 普通级别,日志量较多,接入时建议使用
// tim.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用
// 注册 COS SDK 插件
tim.registerPlugin({
  &#39;cos-wx-sdk&#39;: COS
});
const app = getApp()
let recorderManager = wx.getRecorderManager();
// 录音部分参数 小程序文档
const recordOptions = {
  duration: 60000, // 录音的时长,单位 ms,最大值 600000(10 分钟)
  sampleRate: 44100, // 采样率
  numberOfChannels: 1, // 录音通道数
  encodeBitRate: 192000, // 编码码率
  format: &#39;aac&#39; // 音频格式,选择此格式创建的音频消息,可以在即时通信 IM 全平台(Android、iOS、微信小程序和Web)互通
};
Page({
  data: {
    friendId: &#39;&#39;,
    friendName: &#39;&#39;,
    friendAvatarUrl: &#39;&#39;,
    messages: [], // 消息集合
    complete: 0, // 是否还有历史消息可以拉取,1 - 表示没有,0 - 表示有
    content: &#39;&#39;, // 输入框的文本值
    lock: false, // 发送消息锁 true - 加锁状态 false - 解锁状态
    scroll_height: wx.getSystemInfoSync().windowHeight - 54,
    reply_height: 0,
    moreShow: true,
    userData: [],
    
    audioPng:"../image/audio-play.png",
    audioGif:"../image/audio-play.gif",
    audioState:true,
    /**
     * 历史消息消息集合(结构如下):
     * nextReqMessageID 用于续拉,分页续拉时需传入该字段。
     * isCompleted 表示是否已经拉完所有消息。
     */
    nextReqMessageID: "",
    isCompleted: "",
    isFirstGetList: true,
    audioContext: null,
    opration: true,
    touchBtn: false,
    recording: false,
    stopflag: false,
    cancelRecord: false,
    refreshTime: &#39;&#39;,
    ScrollLoading: 0,
    audioIndex:null,
    sendBtn:true
  },
  onLoad: function (options) {
    // 
    this.setData({
      friendId: options.friendId,
      friendName: options.friendName,
      friendAvatarUrl: options.friendAvatarUrl,
      conversationID: options.conversationID
    })
    wx.setNavigationBarTitle({
      title: options.friendName
    })
    var that = this
    var userData = JSON.parse(wx.getStorageSync(&#39;userData&#39;))
    that.data.messages = [] // 清空历史消息
    let audioContext = wx.createInnerAudioContext()
    this.setData({
      userData,
      audioContext
    })
    // 将某会话下所有未读消息已读上报
    let promise = tim.setMessageRead({ conversationID: options.conversationID });
    promise.then(function (imResponse) {
      // 已读上报成功
    }).catch(function (imError) {
      // 已读上报失败
    });
  },
  onShow: function () {
    let that = this;
    // 获取当前聊天的历史列表
    that.getMessageList();
    that.scrollToBottom();
    // 获取收到的单聊信息
    let onMessageReceived = function (event) {
      // event.data - 存储 Message 对象的数组 - [Message]
      let msgList = that.data.messages
      handlerHistoryMsgs(event.data, that)
      that.scrollToBottom();
    };
    tim.on(TIM.EVENT.MESSAGE_RECEIVED, onMessageReceived)
    // 监听录音结束
    recorderManager.onStop(function (res) {
      if (that.data.recording) {
        if (that.data.cancelRecord) {
          wx.hideToast()
          that.setData({
            cancelRecord: false
          })
        } else {
          // 创建消息实例,接口返回的实例可以上屏
          const message = tim.createAudioMessage({
            to: that.data.friendId,
            conversationType: TIM.TYPES.CONV_C2C,
            payload: {
              file: res
            },
            onProgress: function (event) { }
          });
          //  发送消息
          let promise = tim.sendMessage(message);
          promise.then(function (imResponse) {
            // 发送成功
            that.addMessage(imResponse.data.message, that)
          }).catch(function (imError) {
            // 发送失败
          });
          that.setData({
            recording: false
          })
        }
      } else {
        wx.showToast({
          title: &#39;说话时间太短&#39;,
          duration: 1000,
          image: &#39;../image/err.png&#39;
        })
      }
    });
  },
  onUnload: function () {
  },
  /**
   * 获取消息列表
   */
  getMessageList() {
    let that = this;
    let cb = tim.getMessageList({
      conversationID: conversationID,//会话列表传递过来的参数
      count: 15
    })
    cb.then(function (imResponse) {
      const messageList = imResponse.data.messageList; // 消息列表。
      const nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。
      const isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。
      that.setData({
        nextReqMessageID: nextReqMessageID,
        isCompleted: isCompleted
      })
      handlerHistoryMsgs(messageList, that);
      that.scrollToBottom();
    });
  },
  /**
   * 获取文本的消息
   */
  getContent: function (e) {
    if(e.detail.value ==""){
      this.setData({sendBtn:true})
    }else{
      this.setData({sendBtn:false})
    }
    console.log(e)
    var that = this;
    that.setData({
      content: e.detail.value
    })
  },
  /**
   * 发送消息
   */
  sendMsg: function (e) {
    if(this.data.content ==""){
      wx.showToast({
        title: &#39;请输入内容&#39;,
        duration: 1000,
        icon:&#39;none&#39;
      })
      return
    }
    var that = this
    // 发送文本消息,Web 端与小程序端相同
    // 1. 创建消息实例,接口返回的实例可以上屏
    let message = tim.createTextMessage({
      to: this.data.friendId,
      conversationType: TIM.TYPES.CONV_C2C,
      payload: {
        text: this.data.content
      }
    });
    // 2. 发送消息
    let promise = tim.sendMessage(message);
    promise.then(function (imResponse) {
      // 发送成功
      that.addMessage(imResponse.data.message, that)
      that.setData({sendBtn:true})
    }).catch(function (imError) {
      // 发送失败
    });
  },
  /**
   * 刷新文本消息
   */
  addMessage: function (msg, that) {
    var messages = that.data.messages;
    messages.push(msg);
    that.setData({
      messages: messages,
      content: &#39;&#39; // 清空输入框文本
    })
    that.scrollToBottom();
  },
  /**
   * 发送图片消息
   */
  sendImg() {
    let that = this;
    wx.chooseImage({
      sourceType: [&#39;album&#39;], // 从相册选择
      count: 1, // 只选一张,目前 SDK 不支持一次发送多张图片
      success: function (res) {
        // 2. 创建消息实例,接口返回的实例可以上屏
        let message = tim.createImageMessage({
          to: that.data.friendId,
          conversationType: TIM.TYPES.CONV_C2C,
          payload: {
            file: res
          },
          onProgress: function (event) {
          }
        });
        // 3. 发送图片
        let promise = tim.sendMessage(message);
        promise.then(function (imResponse) {
          // 发送成功
          that.addMessage(imResponse.data.message, that)
        }).catch(function (imError) {
          // 发送失败
        });
      }
    })
  },
  scrollToBottom: function () {
    this.setData({
      toView: &#39;row_&#39; + (this.data.messages.length - 1)
    });
  },
  previewImage(e) {
    let src = &#39;&#39;;
    wx.previewImage({
      current: e.currentTarget.dataset.src, // 当前显示图片的http链接
      urls: [e.currentTarget.dataset.src]
    })
  },
  // 录制语音
  startAudio: function () {
    wx.showToast({
      title: &#39;上滑取消发送&#39;,
      duration: 10000,
      image: &#39;../image/cancel.png&#39;
    })
    this.setData({
      touchBtn: true
    })
    if (this.data.stopFlag) {
      return;
    }
    recorderManager.start(recordOptions);
    recorderManager.onError(function (errMsg) {
    });
  },
  // # 利用长按判断录音是否太短
  onLongpress() {
    this.setData({
      recording: true
    })
  },
  // 发送录音
  onTouchEnd: function () {
    wx.hideToast()
    let that = this;
    that.setData({
      touchBtn: false
    })
    if (that.data.stopFlag) {
      return;
    }
    if (that.data.recording) {
      recorderManager.stop();
    } else {
      that.setData({
        stopFlag: true
      })
      setTimeout(() => {
        recorderManager.stop();
        that.setData({
          stopFlag: false
        })
      }, 400);
    }
  },
  // 播放语音
  openAudio(audio) {
    console.log(audio)
    let index = audio.currentTarget.dataset.eventid
    this.setData({
      audioIndex:index
      // audioState:false
    })
    this.data.audioContext.src = audio.currentTarget.dataset.comkey
    this.data.audioContext.autoplay = true;
    this.data.audioContext.play()
    this.data.audioContext.onPlay((res) => {
    })
    this.data.audioContext.onEnded(() => {
      wx.hideToast()
      this.setData({
        audioIndex:null
      })
      console.log("语音结束了")
    })
    this.data.audioContext.onError((res) => {
    })
  },
  // 上滑取消
  onTouchMove(e) {
    if (e.touches[0].clientY < 520) {
      // # 取消发送
      this.setData({
        cancelRecord: true
      });
      wx.showToast({
        title: &#39;松开,取消发送&#39;,
        duration: 10000,
        image: &#39;../image/cancel.png&#39;
      })
    } else {
      // # 不取消
      wx.hideToast()
      wx.showToast({
        title: &#39;上滑取消发送&#39;,
        duration: 10000,
        image: &#39;../image/cancel.png&#39;
      })
      this.setData({
        cancelRecord: false
      })
    }
  },
  // 下拉加载聊天记录
  refresh: function (e) {
    let that = this
    if (that.data.ScrollLoading == 1) { //防止多次触发
      return false
    }
    if (e.detail.scrollTop < 1) {
      that.setData({ ScrollLoading: 1 })
      wx.showLoading({
        title: &#39;加载中&#39;,
      })
      setTimeout(() => {
        let promise = tim.getMessageList({ conversationID: that.data.conversationID, nextReqMessageID: that.data.nextReqMessageID, count: 15 });
        promise.then(function (imResponse) {
          const newMessageList = imResponse.data.messageList; // 消息列表。
          const nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。
          const isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。
          that.setData({
            nextReqMessageID: nextReqMessageID,
            isCompleted: isCompleted,
            messages: newMessageList.concat(that.data.messages)
          })
          wx.hideLoading()
          that.setData({ ScrollLoading: 0 })
          // handlerHistoryMsgs(messageList, that);
        });
      }, 800);
    }
    // setTimeout(function(){
    //   var date = new Date();
    // },300);
  },
  // 切换
  Audio() {
    this.setData({
      opration: false
    })
  },
  keyboard() {
    this.setData({
      opration: true
    })
  },
  moreClick() {
    if (this.data.moreShow) {
      this.setData({
        moreShow: false,
        reply_height: 92,
        scroll_height: this.data.scroll_height - 92
      })
    }
  },
  bindfocus() {
    this.setData({
      moreShow: true,
      reply_height: 0,
      scroll_height: wx.getSystemInfoSync().windowHeight - 54
    })
  }
})
/**
 * 处理历史消息 
 */
function handlerHistoryMsgs(result, that) {
  var historyMsgs = that.data.messages;
  result.forEach(item => {
    historyMsgs.push(item)
  })
  // historyMsgs.push(result[0])
  that.setData({
    messages: historyMsgs,
  })
    // 将某会话下所有未读消息已读上报
    let promise = tim.setMessageRead({ conversationID: that.data.conversationID });
    promise.then(function (imResponse) {
      // 已读上报成功
    }).catch(function (imError) {
      // 已读上报失败
    });
}

wxss:


/** 聊天窗口样式
 * 54px为回复框高度,js同
 */
/*聊天记录*/
page{
  background: rgb(245, 245, 245);
}
.message-list {
  /*margin-bottom: 54px;*/
  background: rgb(235, 235, 235);
}
/*单元行*/
.row {
  display: flex;
  flex-direction: column;
  margin: 0 30rpx;
}
/*日期*/
.datetime {
  font-size: 10px;
  padding: 10px 0;
  color: #999;
  text-align: center;
}
.send {
  font-size: 15px;
  /* padding-right: 10px; */
  color: #999;
  text-align: center;
  height: 70%;
  border: 1px solid #e4dfdf;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 90rpx;
  border-radius: 10rpx;
}
.sendActive {
  font-size: 15px;
  /* padding-right: 10px; */
  color: #fff;
  text-align: center;
  height: 70%;
  border: 1px solid #05c15f;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 90rpx;
  border-radius: 10rpx;
  background-color: #05c15f;
}
.Audio {
  font-size: 15px;
  color: #999;
  text-align: center;
  padding-left: 10rpx;
}
.Audio image {
  width: 50rpx;
  height: 50rpx;
}
.add {
  height: 70%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 90rpx;
}
.more {
  width: 50rpx;
  height: 50rpx;
}
/*主体*/
.body {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
  width: 100%;
  margin-top: 10px;
}
/*头像容器*/
.body.avatar-container {
  width: 20%;
}
/*头像*/
.body .avatar {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  margin: 0 20rpx;
}
/*文本消息*/
.body .content {
  font-size: 16px;
  background: #fff;
  border-radius: 5px;
  padding: 10px;
  line-height: 22px;
  margin-bottom: 10px;
  word-wrap: break-word;
  max-width: 300rpx;
}
/* 三角箭头 */
.body .triangle {
  background: white;
  width: 20rpx;
  height: 20rpx;
  margin-top: 26rpx;
  transform: rotate(45deg);
  position: absolute;
}
/*图片消息*/
.picture {
  width: 160px;
}
/*回复框*/
.reply {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  position: fixed;
  /* bottom: 0; */
  width: 100%;
  height: 54px;
  border-top: 1px solid rgb(215, 215, 215);
  background: rgb(245, 245, 245);
}
.reply .voice-image {
  width: 25px;
  height: 25px;
  margin-left: 3%;
}
/*文本输入或语音录入*/
.reply .opration-area {
  flex: 1;
  padding: 8px;
}
/*回复文本框*/
.reply input {
  background: rgb(252, 252, 252);
  height: 36px;
  border: 1px solid rgb(221, 221, 221);
  border-radius: 6px;
  padding-left: 3px;
}
/*选取图片*/
.reply .choose-image {
  width: 25px;
  height: 25px;
  margin-right: 3%;
}
/*按住说话button*/
.voice-button {
  height: 36px;
  color: #818181;
  font-size: 14px;
  line-height: 36px;
  text-align: center;
  border: 1px solid #e4dfdf;
  border-radius: 10rpx;
}
/*悬浮提示框*/
.hud-container {
  position: fixed;
  width: 150px;
  height: 150px;
  left: 50%;
  top: 50%;
  margin-left: -75px;
  margin-top: -75px;
}
/*背景层*/
.hud-background {
  position: absolute;
  width: 100%;
  height: 100%;
  background: #999;
  opacity: 0.8;
  z-index: 11;
  border-radius: 10px;
}
/*悬浮框主体*/
.hud-body {
  position: relative;
  width: 100%;
  height: 100%;
  z-index: 19;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
}
/*图标*/
.hud-body image {
  margin-top: 20px;
  width: 80px;
  height: 80px;
}
/*文字*/
.hud-body .tip {
  color: #fff;
  text-align: center;
  width: 90%;
  line-height: 34px;
  margin: 0 auto;
  margin-bottom: 10px;
  width: 90%;
}
.hud-body .warning {
  background: #c33;
  border-radius: 5px;
}
.image-message {
  max-width: 100%;
  border-radius: 4rpx;
}
.box {
  display: flex;
  height: 40rpx;
  line-height: 40rpx;
}
.hoverBtn {
  background-color: rgb(226, 220, 220);
  color: #fff;
  border-radius: 10rpx;
}
.more_box {
height: 138rpx;
width: 100%;
padding: 15rpx;
display: flex;
background: rgb(245, 245, 245);
position: fixed;
bottom: 0;
}
.more_item {
  text-align: center;
  height: 150rpx;
  font-size: 24rpx;
  margin-left: 26rpx
}
.img_box {
  width: 80rpx;
  height: 84rpx;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 10rpx;
}
.img_box image {
  width: 40rpx;
  height: 40rpx;
}

推奨チュートリアル: 「

小規模プログラム開発

以上がミニプログラムにSDKをインポートしてチャット機能を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。