当前位置:   article > 正文

uniapp+websocket聊天功能实现(超详细!!附代码,可直接复用)_uniapp使用websocket建立聊天室

uniapp使用websocket建立聊天室

最近项目上用到了聊天的功能,下面来分享一下关于websocket,键盘弹出等问题,避免别的朋友踩坑。

先给大家看看效果图 

 接着进入正文了!!!!!

一、需要注意的几个点

1.scroll-view的高度

先看看整体的页面布局

 system.windowHeight : 页面总高度

totalHeight:顶部导航栏高度

sendHeight:底部输入框高度 (设置样式的时候自己设置的)

keyboardHeight:键盘高度(键盘没有弹出的时候为0)

  1. uni.getSystemInfo({
  2. success: res => {
  3. this.system = res
  4. }
  5. })
  6. // #ifdef MP-WEIXIN
  7. //获取胶囊信息
  8. this.menu = uni.getMenuButtonBoundingClientRect()
  9. //计算组件高度
  10. this.statusBarHeight = this.system.statusBarHeight //状态栏高度
  11. this.navigatorHeight = (this.menu.top - this.system.statusBarHeight) * 2 + this.menu.height //导航栏高度
  12. this.totalHeight = this.statusBarHeight + this.navigatorHeight //总高度
  13. // 保存到全局
  14. this.$store.state.totalHeight = this.totalHeight
  15. this.$store.state.system = this.system
  16. // #endif
  17. // #ifdef APP
  18. this.statusBarHeight = this.system.statusBarHeight //状态栏高度
  19. this.navigatorHeight = this.system.statusBarHeight + 45 //导航栏高度
  20. this.totalHeight = this.navigatorHeight //总高度
  21. // 保存到全局
  22. this.$store.state.totalHeight = this.totalHeight
  23. this.$store.state.system = this.system
  24. // #endif

这里需要注意的是scroll-view没有高度就和view差不多,scroll-into-view属性就不生效。

2.键盘弹起时,使页面向上移动,顶部导航栏不动

使用textarea原生的键盘弹起时,页面向上移是这样的

 解决后的图片:

 是不是看着顺眼多了

首先的话需要在页面加载的时候监听一下键盘的高度

  1. listenerKeyboardHeight() {
  2. this.listener = (res) => {
  3. console.log("键盘高度", res.height)
  4. this.keyboardHeight = res.height
  5. this.$nextTick(() => {
  6. this.scrollToBottom()
  7. })
  8. }
  9. uni.onKeyboardHeightChange(this.listener)
  10. }

当键盘弹出的时候,将scroll-view的高度减去键盘高度,底部发送框向上移动‘键盘高度’的px

底部的发送框一般都是position: fixed;来定位的,将bottom属性变一下就行了

  1. <view class="information-box lky-flex-items-center" :style="{bottom: bottom+'px'}">
  2. <view style="margin-right: 20rpx; width: 100%">
  3. <u--textarea :confirmType="null" v-model="value" placeholder="请输入" height="40rpx" :showConfirmBar="false"
  4. :placeholderStyle="placeholderStyle" @focus="textfocus" :adjustPosition="false" />
  5. </view>
  6. <image src="@/static/images/chat/icon_attachment.svg" class="icon" v-if="isUploadFile" @click="openFile" />
  7. <image src="@/static/images/chat/icon_send.svg" class="icon" @click="send" />
  8. </view>

3.定位到底部

先再来看看我们的页面布局

最后一条是用于定位到底部的

  1. <!-- 用于定位到底部 -->
  2. <view id="last-msg-item" style="height: 1px;"></view>

方法:

  1. // 定位到底部
  2. scrollToBottom() {
  3. this.$nextTick(() => {
  4. this.scrollIntoView = "last-msg-item"
  5. // 清空,为下一次定位做准备
  6. this.$nextTick(() => {
  7. this.scrollIntoView = ""
  8. })
  9. })
  10. },

二、websocket代码

这是封装的一个mixin类

  1. import {
  2. socket
  3. } from "@/common/mixin/socket.js"
  4. //引入方法
  5. export default {
  6. mixins: [socket],
  7. }

socket.js

  1. export const socket = {
  2. data() {
  3. return {
  4. // socket是否开启
  5. socketOpen: false,
  6. // 定时器
  7. timer: null,
  8. // 链接
  9. surl: `websocket链接`,
  10. // 底部id用于定位到底部
  11. scrollIntoView: "",
  12. // 键盘高度
  13. keyboardHeight: 0,
  14. // 监听键盘高度的方法
  15. listener: null
  16. }
  17. },
  18. onLoad(option) {
  19. // 开启键盘高度监听
  20. this.listenerKeyboardHeight()
  21. // socket初始化
  22. this.init()
  23. // 定时器,定时判断socket有没有掉线
  24. this.timer = setInterval(() => {
  25. this.isSocketConnct()
  26. }, 2000)
  27. },
  28. beforeDestroy() {
  29. // 关闭定时器
  30. clearInterval(this.timer)
  31. // 关闭键盘高度监听
  32. uni.offKeyboardHeightChange(this.listener)
  33. // 关闭Socket
  34. this.closeSocket()
  35. },
  36. methods: {
  37. // 发送消息
  38. sendSocketMessage(msg) {
  39. console.log("发送消息", msg);
  40. let that = this
  41. if (this.socketOpen) {
  42. uni.sendSocketMessage({
  43. data: msg,
  44. success: (res) => {
  45. setTimeout(() => {
  46. // json转对象
  47. let param = JSON.parse(msg)
  48. that.sendMessageHandle(param)
  49. }, 300)
  50. },
  51. fail(err) {
  52. // 发送失败处理
  53. }
  54. });
  55. } else {
  56. // Socket没有开启,重新连接并重新发送消息
  57. this.init()
  58. setTimeout(() => {
  59. this.sendSocketMessage(msg)
  60. },300)
  61. }
  62. },
  63. // 判断是否连接
  64. isSocketConnct() {
  65. if (!this.socketOpen) {
  66. console.log("WebSocket 再次连接!");
  67. this.init()
  68. }
  69. },
  70. // 初始化
  71. init() {
  72. this.connect()
  73. this.openSocket()
  74. this.onclose()
  75. this.onSocketMessage()
  76. },
  77. // 建立连接
  78. connect() {
  79. console.log(this.surl);
  80. uni.connectSocket({
  81. url: this.surl,
  82. method: 'GET'
  83. });
  84. },
  85. // 监听关闭
  86. onclose() {
  87. let that = this
  88. uni.onSocketClose((res) => {
  89. that.socketOpen = false
  90. console.log('WebSocket 已关闭!');
  91. });
  92. },
  93. // 关闭
  94. closeSocket() {
  95. uni.closeSocket();
  96. },
  97. // 打开Soceket
  98. openSocket() {
  99. let that = this
  100. uni.onSocketOpen((res) => {
  101. that.socketOpen = true
  102. console.log('WebSocket连接已打开!');
  103. });
  104. },
  105. // 接收事件
  106. onSocketMessage() {
  107. let that = this
  108. uni.onSocketMessage((res) => {
  109. let obj = JSON.parse(res.data)
  110. console.log("接收事件", obj);
  111. this.onMessageHandle(obj)
  112. });
  113. },
  114. // 接收到事件后处理的方法(可自己重写)
  115. onMessageHandle(obj) {
  116. // 根据自己业务逻辑重写
  117. },
  118. // 发送消息后处理的方法(可自己重写)
  119. sendMessageHandle(msg) {
  120. // 根据自己业务逻辑重写
  121. },
  122. // 定位到底部
  123. scrollToBottom() {
  124. this.$nextTick(() => {
  125. this.scrollIntoView = "last-msg-item"
  126. this.$nextTick(() => {
  127. this.scrollIntoView = ""
  128. })
  129. })
  130. },
  131. // 开启键盘高度的监听
  132. listenerKeyboardHeight() {
  133. this.listener = (res) => {
  134. console.log("键盘高度", res.height)
  135. this.keyboardHeight = res.height
  136. this.$nextTick(() => {
  137. this.scrollToBottom()
  138. })
  139. }
  140. uni.onKeyboardHeightChange(this.listener)
  141. }
  142. }
  143. }

直接引入就可以使用啦 , 接下来说说几个可能用到的方法,在自己的页面直接用就可以啦

  1. // 发送消息方法
  2. send(value) {
  3. // 自定义消息体
  4. let param = {
  5. "type": 1,
  6. "content": value,
  7. }
  8. // 对象转json
  9. let m = JSON.stringify(param)
  10. this.sendSocketMessage(m)
  11. },
  1. // 接收到事件后处理的方法(可自己重写)
  2. onMessageHandle(obj) {
  3. // obj 接收到的事件对象
  4. },
  5. // 发送消息后处理的方法(可自己重写)
  6. sendMessageHandle(msg) {
  7. // msg 发送的消息对象
  8. }

三、页面布局代码

  1. <template>
  2. <view>
  3. <!-- 自定义顶部导航栏 用原生的话下面scroll-view应该可以不用减去导航栏的高度的-->
  4. <u-navbar :placeholder='true' :autoBack='true' leftIconSize='40rpx'>
  5. <view class="navbar-title" slot="center">{{navbarTitle}}</view>
  6. </u-navbar>
  7. <scroll-view
  8. scroll-y="true"
  9. class="content-box" id="chat"
  10. :style="{'height':system.windowHeight - totalHeight - sendHeight - keyboardHeight+'px' }"
  11. :scroll-into-view='scrollIntoView'>
  12. <lky-gap size='40' />
  13. <view id="msglistview"></view>
  14. <view id="last-msg-item" style="height: 1px;"></view>
  15. </scroll-view>
  16. <lky-send
  17. @send="send"
  18. :is-upload-file="false"
  19. @imageSend="imageSend"
  20. @fileSend="fileSend"
  21. :bottom-copy='keyboardHeight'></lky-send>
  22. </view>
  23. </template>
  24. <script>
  25. import {
  26. mapState
  27. } from 'vuex'
  28. import {
  29. socket
  30. } from "@/common/mixin/socket.js"
  31. import LkySend from "../component/lky-p-send/lky-p-send.vue"
  32. export default {
  33. components: {
  34. },
  35. mixins: [socket],
  36. data() {
  37. return {
  38. src: '',
  39. // 聊天记录列表
  40. messageList: [],
  41. // socket链接,如果在socket.js中改了的话就不用写这个了
  42. surl: ``,
  43. };
  44. },
  45. // 我的高度存在vuex的
  46. computed: mapState([
  47. "totalHeight", "system", "sendHeight"
  48. ]),
  49. onLoad(option) {
  50. // 获取聊天记录
  51. this.messageList = uni.getStorageSync(`messageList_${this.$store.state.userInfo.id}`) || []
  52. console.log("缓存中的聊天记录", this.messageList);
  53. this.scrollToBottom()
  54. },
  55. methods: {
  56. send(value) {
  57. let param = {
  58. "type": 1,
  59. "content": value,
  60. }
  61. let m = JSON.stringify(param)
  62. this.sendSocketMessage(m)
  63. },
  64. // 预览图片
  65. imageClick(url) {
  66. uni.previewImage({
  67. urls: [
  68. url
  69. ]
  70. })
  71. },
  72. // 发送图片
  73. imageSend(url) {
  74. let param = {
  75. "type": 3,
  76. "text": "",
  77. "url": url,
  78. "userId": this.$store.state.userInfo.id
  79. }
  80. let m = JSON.stringify(param)
  81. this.sendSocketMessage(m)
  82. },
  83. // 发送文件
  84. fileSend(url, name) {
  85. let param = {
  86. "type": 4,
  87. "text": name,
  88. "url": url,
  89. "userId": this.$store.state.userInfo.id
  90. }
  91. let m = JSON.stringify(param)
  92. this.sendSocketMessage(m)
  93. },
  94. // 打开文件
  95. openFile(item) {
  96. uni.downloadFile({
  97. url: item.url,
  98. success: (res) => {
  99. var filePath = res.tempFilePath;
  100. uni.openDocument({
  101. filePath: filePath,
  102. showMenu: true,
  103. success: function(res) {}
  104. });
  105. }
  106. });
  107. },
  108. // 接收到事件后处理的方法(可自己重写)
  109. onMessageHandle(obj) {
  110. //根据业务逻辑重写
  111. // obj接收到的事件
  112. },
  113. // 发送消息后处理的方法(可自己重写)
  114. sendMessageHandle(msg) {
  115. //根据业务逻辑重写
  116. // msg 发送的消息
  117. },
  118. }
  119. }
  120. </script>
  121. <style lang="scss">
  122. body {
  123. box-sizing: border-box;
  124. padding: 0 ;
  125. background-color: $lky-hui-bg ;
  126. }
  127. </style>
  128. <style lang="scss" scoped>
  129. .content-box {
  130. padding: 0 28rpx;
  131. box-sizing: border-box;
  132. height: auto;
  133. z-index: -1;
  134. overflow: hidden;
  135. }
  136. </style>

到这里一个聊天的功能就结束了 ,这应该已经很详细了,其余的自己根据自己的业务逻辑和ui进行调整就行了!


最后有什么不足的地方也请各位指正优化一下

结束!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/105091
推荐阅读
相关标签
  

闽ICP备14008679号