index.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <template>
  2. <scroll-view
  3. class="message-list-container"
  4. scroll-y="true"
  5. :scroll-into-view="scrollView"
  6. :refresher-enabled="true"
  7. @refresherrefresh="refresh"
  8. :scroll-top="scrollTop"
  9. :refresher-triggered="triggered"
  10. >
  11. <view id="message-scroll" style="width:100%">
  12. <view class="no-message" v-if="isCompleted">没有更多啦</view>
  13. <view v-for="item in messageList" :key="item.ID" class="t-message">
  14. <view v-if="conversation.type !== '@TIM#SYSTEM'" :id="item.ID">
  15. <view class="t-message-item">
  16. <TUI-TipMessage v-if="item.type === 'TIMGroupTipElem'" :message="item"></TUI-TipMessage>
  17. <view v-if="item.type !== 'TIMGroupTipElem'" :class="item.flow === 'out' ? 't-self-message' : 't-recieve-message'">
  18. <image
  19. class="t-message-avatar"
  20. v-if="item.flow === 'in'"
  21. :src="item.avatar || 'https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/component/TUIKit/assets/avatar_21.png'"
  22. ></image>
  23. <view class="read-receipts" v-if="conversation.type === 'C2C' && item.flow === 'out'">
  24. <view v-if="item.isPeerRead">已读</view>
  25. <view v-else>未读</view>
  26. </view>
  27. <view>
  28. <TUI-TextMessage v-if="item.type === 'TIMTextElem'" :message="item" :isMine="item.flow === 'out'"></TUI-TextMessage>
  29. <TUI-ImageMessage v-if="item.type === 'TIMImageElem'" :message="item" :isMine="item.flow === 'out'"></TUI-ImageMessage>
  30. <TUI-VideoMessage v-if="item.type === 'TIMVideoFileElem'" :message="item" :isMine="item.flow === 'out'"></TUI-VideoMessage>
  31. <TUI-AudioMessage v-if="item.type === 'TIMSoundElem'" :message="item" :isMine="item.flow === 'out'"></TUI-AudioMessage>
  32. <TUI-CustomMessage v-if="item.type === 'TIMCustomElem'" :message="item" :isMine="item.flow === 'out'"></TUI-CustomMessage>
  33. <TUI-FaceMessage v-if="item.type === 'TIMFaceElem'" :message="item" :isMine="item.flow === 'out'"></TUI-FaceMessage>
  34. <TUI-FileMessage v-if="item.type === 'TIMFileElem'" :message="item" :isMine="item.flow === 'out'"></TUI-FileMessage>
  35. </view>
  36. <image
  37. class="t-message-avatar"
  38. v-if="item.flow === 'out'"
  39. :src="item.avatar || 'https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/component/TUIKit/assets/avatar_21.png'"
  40. ></image>
  41. </view>
  42. </view>
  43. </view>
  44. <view v-else :id="item.ID" :data-value="item.ID"><TUI-SystemMessage :message="item"></TUI-SystemMessage></view>
  45. </view>
  46. </view>
  47. </scroll-view>
  48. </template>
  49. <script>
  50. import TUITextMessage from '../message-elements/text-message/index';
  51. import TUIImageMessage from '../message-elements/image-message/index';
  52. import TUIVideoMessage from '../message-elements/video-message/index';
  53. import TUIAudioMessage from '../message-elements/audio-message/index';
  54. import TUICustomMessage from '../message-elements/custom-message/index';
  55. import TUITipMessage from '../message-elements/tip-message/index';
  56. import TUISystemMessage from '../message-elements/system-message/index';
  57. import TUIFaceMessage from '../message-elements/face-message/index';
  58. import TUIFileMessage from '../message-elements/file-message/index';
  59. export default {
  60. data() {
  61. return {
  62. avatar: '',
  63. userID: '',
  64. // 当前会话
  65. messageList: [],
  66. // 自己的 ID 用于区分历史消息中,哪部分是自己发出的
  67. scrollView: '',
  68. scrollTop: 0,
  69. triggered: true,
  70. nextReqMessageID: '',
  71. // 下一条消息标志
  72. isCompleted: false // 当前会话消息是否已经请求完毕
  73. };
  74. },
  75. components: {
  76. TUITextMessage,
  77. TUIImageMessage,
  78. TUIVideoMessage,
  79. TUIAudioMessage,
  80. TUICustomMessage,
  81. TUITipMessage,
  82. TUISystemMessage,
  83. TUIFaceMessage,
  84. TUIFileMessage
  85. },
  86. props: {
  87. conversation: {
  88. type: Object,
  89. default: () => {}
  90. }
  91. },
  92. watch: {
  93. conversation: {
  94. handler: function(newVal) {
  95. if (!newVal.conversationID) return;
  96. this.setData(
  97. {
  98. conversation: newVal
  99. },
  100. () => {
  101. this.getMessageList(newVal);
  102. }
  103. );
  104. },
  105. immediate: true,
  106. deep: true
  107. }
  108. },
  109. mounted() {
  110. uni.$TUIKit.getMyProfile().then(res => {
  111. this.avatar = res.data.avatar;
  112. this.userID = res.data.userID;
  113. });
  114. uni.$TUIKit.on(uni.$TUIKitEvent.MESSAGE_RECEIVED, this.$onMessageReceived, this);
  115. uni.$TUIKit.on(uni.$TUIKitEvent.MESSAGE_READ_BY_PEER, this.$onMessageReadByPeer, this);
  116. },
  117. destroyed() {
  118. // 一定要解除相关的事件绑定
  119. uni.$TUIKit.off(uni.$TUIKitEvent.MESSAGE_RECEIVED, this.$onMessageReceived);
  120. },
  121. methods: {
  122. refresh() {
  123. if (this.isCompleted) {
  124. this.setData({
  125. isCompleted: true,
  126. triggered: false
  127. });
  128. return;
  129. }
  130. this.getMessageList(this.conversation);
  131. setTimeout(() => {
  132. this.setData({
  133. triggered: false
  134. });
  135. }, 2000);
  136. },
  137. getMessageList(conversation) {
  138. if (!this.isCompleted) {
  139. uni.$TUIKit
  140. .getMessageList({
  141. conversationID: conversation.conversationID,
  142. nextReqMessageID: this.nextReqMessageID,
  143. count: 15
  144. })
  145. .then(res => {
  146. const { messageList } = res.data; // 消息列表。
  147. this.nextReqMessageID = res.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。
  148. this.isCompleted = res.data.isCompleted; // 表示是否已经拉完所有消息。
  149. this.messageList = [...messageList, ...this.messageList];
  150. this.$handleMessageRender(this.messageList, messageList);
  151. });
  152. }
  153. },
  154. // 自己的消息上屏
  155. updateMessageList(msg) {
  156. this.messageList = [...this.messageList, msg];
  157. this.scrollToButtom();
  158. },
  159. // 消息已读更新
  160. $onMessageReadByPeer() {
  161. this.setData({
  162. messageList: this.messageList
  163. });
  164. },
  165. scrollToButtom() {
  166. const query = uni.createSelectorQuery().in(this);
  167. let nodesRef = query.select('#message-scroll');
  168. nodesRef
  169. .boundingClientRect(res => {
  170. this.$nextTick(() => {
  171. //进入页面滚动到底部
  172. this.scrollTop = res.height;
  173. });
  174. })
  175. .exec();
  176. },
  177. // 收到的消息
  178. $onMessageReceived(value) {
  179. // 若需修改消息,需将内存的消息复制一份,不能直接更改消息,防止修复内存消息,导致其他消息监听处发生消息错误
  180. const event = value;
  181. const list = [];
  182. event.data.forEach(item => {
  183. if (item.conversationID === this.conversation.conversationID) {
  184. list.push(Object.assign(item));
  185. }
  186. });
  187. this.messageList = this.messageList.concat(list);
  188. this.scrollToButtom();
  189. },
  190. // 历史消息渲染
  191. $handleMessageRender(messageList) {
  192. if (messageList.length > 0) {
  193. this.setData(
  194. {
  195. messageList
  196. },
  197. () => {}
  198. );
  199. this.$nextTick(() => {
  200. //进入页面滚动到底部
  201. this.scrollTop = 9999;
  202. });
  203. }
  204. }
  205. }
  206. };
  207. </script>
  208. <style>
  209. @import './index.css';
  210. </style>