Selaa lähdekoodia

增加回到消息底部功能

xsx 9 kuukautta sitten
vanhempi
commit
ab9763fd94
2 muutettua tiedostoa jossa 140 lisäystä ja 71 poistoa
  1. 49 16
      im-uniapp/pages/chat/chat-box.vue
  2. 91 55
      im-web/src/components/chat/ChatBox.vue

+ 49 - 16
im-uniapp/pages/chat/chat-box.vue

@@ -15,6 +15,9 @@
 						</chat-message-item>
 					</view>
 				</scroll-view>
+				<view v-if="!isInBottom" class="scroll-to-bottom" @click="onClickToBottom">
+					{{ newMessageSize > 0 ?  newMessageSize+'条新消息' :'回到底部'}}
+				</view>
 			</view>
 			<view v-if="atUserIds.length > 0" class="chat-at-bar" @click="openAtBox()">
 				<view class="iconfont icon-at">&nbsp;</view>
@@ -140,7 +143,9 @@ export default {
 			isEmpty: true, // 编辑器是否为空
 			isFocus: false, // 编辑器是否焦点
 			isReadOnly: false, // 编辑器是否只读
-			playingAudio: null // 当前正在播放的录音消息
+			playingAudio: null, // 当前正在播放的录音消息
+			isInBottom: true, // 滚动条是否在底部
+			newMessageSize: 0 // 滚动条不在底部时新的消息数量
 		}
 	},
 	methods: {
@@ -561,17 +566,32 @@ export default {
 				}
 			});
 		},
+		onClickToBottom() {
+			this.scrollToBottom();
+			// 有些设备滚到底部时会莫名触发滚动到顶部的事件
+			// 所以这里延迟100s保证能准确设置底部标志
+			setTimeout(() => {
+				this.isInBottom = true;
+				this.newMessageSize = 0;
+			}, 100)
+		},
 		onScrollToTop() {
-			if (this.showMinIdx == 0) {
-				console.log("消息已滚动到顶部")
-				return;
+			console.log("onScrollToTop")
+			if (this.showMinIdx > 0) {
+				//  #ifndef H5
+				// 防止滚动条定格在顶部,不能一直往上滚
+				this.scrollToMsgIdx(this.showMinIdx);
+				// #endif
+				// 多展示20条信息
+				this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0;
 			}
-			//  #ifndef H5
-			// 防止滚动条定格在顶部,不能一直往上滚
-			this.scrollToMsgIdx(this.showMinIdx);
-			// #endif
-			// 多展示20条信息
-			this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0;
+			// 清除底部标识
+			this.isInBottom = false;
+		},
+		onScrollToBottom(e) {
+			// 设置底部标识
+			this.isInBottom = true;
+			this.newMessageSize = 0;
 		},
 		onShowMore() {
 			if (this.chat.type == "GROUP") {
@@ -639,7 +659,6 @@ export default {
 				method: 'PUT'
 			}).then(() => {
 				this.chatStore.resetUnreadCount(this.chat)
-				this.scrollToBottom();
 			})
 		},
 		loadGroup(groupId) {
@@ -907,12 +926,12 @@ export default {
 		messageSize: function(newSize, oldSize) {
 			// 接收到消息时滚动到底部
 			if (newSize > oldSize) {
-				let pages = getCurrentPages();
-				let curPage = pages[pages.length - 1].route;
-				if (curPage == "pages/chat/chat-box") {
+				if (this.isInBottom) {
+					// 收到消息,则滚动至底部
 					this.scrollToBottom();
 				} else {
-					this.needScrollToBottom = true;
+					// 若滚动条不在底部,说明用户正在翻历史消息,此时滚动条不能动,同时增加新消息提示
+					this.newMessageSize++;
 				}
 			}
 		},
@@ -949,7 +968,8 @@ export default {
 		// 计算聊天窗口高度
 		this.$nextTick(() => {
 			this.windowHeight = uni.getSystemInfoSync().windowHeight;
-			this.reCalChatMainHeight()
+			this.reCalChatMainHeight();
+			this.scrollToBottom();
 			// #ifdef H5
 			this.initHeight = window.innerHeight;
 			// 兼容ios的h5:禁止页面滚动
@@ -1025,6 +1045,19 @@ export default {
 			.scroll-box {
 				height: 100%;
 			}
+
+			.scroll-to-bottom {
+				position: absolute;
+				right: 30rpx;
+				bottom: 30rpx;
+				font-size: $im-font-size;
+				color: $im-color-primary;
+				font-weight: 600;
+				background: white;
+				padding: 10rpx 30rpx;
+				border-radius: 25rpx;
+				box-shadow: $im-box-shadow-dark;
+			}
 		}
 
 		.chat-at-bar {

+ 91 - 55
im-web/src/components/chat/ChatBox.vue

@@ -22,6 +22,9 @@
 								</ul>
 							</div>
 						</el-main>
+						<div v-if="!isInBottom" class="scroll-to-bottom" @click="scrollToBottom">
+							{{ newMessageSize > 0 ? newMessageSize + '条新消息' : '回到底部' }}
+						</div>
 						<el-footer height="220px" class="im-chat-footer">
 							<div class="chat-tool-bar">
 								<div title="表情" class="icon iconfont icon-emoji" ref="emotion"
@@ -129,8 +132,10 @@ export default {
 			showHistory: false, // 是否显示历史聊天记录
 			lockMessage: false, // 是否锁定发送,
 			showMinIdx: 0, // 下标低于showMinIdx的消息不显示,否则页面会很卡置
-			reqQueue: [],
-			isSending: false
+			reqQueue: [], // 等待发送的请求队列
+			isSending: false, // 是否正在发消息
+			isInBottom: false, // 滚动条是否在底部
+			newMessageSize: 0 // 滚动条不在底部时新的消息数量
 		}
 	},
 	methods: {
@@ -276,6 +281,12 @@ export default {
 			if (scrollTop < 30) { // 在顶部,不滚动的情况
 				// 多展示20条信息
 				this.showMinIdx = this.showMinIdx > 20 ? this.showMinIdx - 20 : 0;
+				this.isInBottom = false;
+			}
+			// 滚到底部
+			if (scrollTop + scrollElement.clientHeight >= scrollElement.scrollHeight - 30) {
+				this.isInBottom = true;
+				this.newMessageSize = 0;
 			}
 		},
 		showEmotionBox() {
@@ -729,8 +740,13 @@ export default {
 		messageSize: {
 			handler(newSize, oldSize) {
 				if (newSize > oldSize) {
-					// 拉至底部
-					this.scrollToBottom();
+					if (this.isInBottom) {
+						// 拉至底部
+						this.scrollToBottom();
+					} else {
+						// 增加新消息提醒
+						this.newMessageSize++;
+					}
 				}
 			}
 		}
@@ -767,72 +783,92 @@ export default {
 		}
 	}
 
-	.im-chat-main {
-		padding: 0;
-		background-color: #fff;
+	.content-box {
+		position: relative;
+
+		.im-chat-main {
+			padding: 0;
+			background-color: #fff;
 
-		.im-chat-box {
-			>ul {
-				padding: 0 20px;
+			.im-chat-box {
+				>ul {
+					padding: 0 20px;
 
-				li {
-					list-style-type: none;
+					li {
+						list-style-type: none;
+					}
 				}
 			}
 		}
-	}
 
-	.im-chat-footer {
-		display: flex;
-		flex-direction: column;
-		padding: 0;
+		.scroll-to-bottom {
+			text-align: right;
+			position: absolute;
+			right: 20px;
+			bottom: 230px;
+			color: var(--im-color-primary);
+			font-size: var(--im-font-size);
+			font-weight: 600;
+			background: #eee;
+			padding: 5px 15px;
+			border-radius: 15px;
+			cursor: pointer;
+			z-index: 99;
+			box-shadow: var(--im-box-shadow-light);
+		}
 
-		.chat-tool-bar {
+		.im-chat-footer {
 			display: flex;
-			position: relative;
-			width: 100%;
-			height: 36px;
-			text-align: left;
-			box-sizing: border-box;
-			border-top: var(--im-border);
-			padding: 4px 2px 2px 8px;
+			flex-direction: column;
+			padding: 0;
+
+			.chat-tool-bar {
+				display: flex;
+				position: relative;
+				width: 100%;
+				height: 36px;
+				text-align: left;
+				box-sizing: border-box;
+				border-top: var(--im-border);
+				padding: 4px 2px 2px 8px;
 
-			>div {
-				font-size: 22px;
-				cursor: pointer;
-				line-height: 30px;
-				width: 30px;
-				height: 30px;
-				text-align: center;
-				border-radius: 2px;
-				margin-right: 8px;
-				color: #999;
-				transition: 0.3s;
+				>div {
+					font-size: 22px;
+					cursor: pointer;
+					line-height: 30px;
+					width: 30px;
+					height: 30px;
+					text-align: center;
+					border-radius: 2px;
+					margin-right: 8px;
+					color: #999;
+					transition: 0.3s;
 
-				&.chat-tool-active {
-					font-weight: 600;
-					color: var(--im-color-primary);
-					background-color: #ddd;
+					&.chat-tool-active {
+						font-weight: 600;
+						color: var(--im-color-primary);
+						background-color: #ddd;
+					}
 				}
-			}
 
-			>div:hover {
-				color: #333;
+				>div:hover {
+					color: #333;
+				}
 			}
-		}
 
-		.send-content-area {
-			position: relative;
-			display: flex;
-			flex-direction: column;
-			height: 100%;
-			background-color: white !important;
+			.send-content-area {
+				position: relative;
+				display: flex;
+				flex-direction: column;
+				height: 100%;
+				background-color: white !important;
 
-			.send-btn-area {
-				padding: 10px;
-				position: absolute;
-				bottom: 4px;
-				right: 6px;
+				.send-btn-area {
+					padding: 10px;
+					position: absolute;
+					bottom: 4px;
+					right: 6px;
+				}
 			}
 		}
 	}