From 5897f3304abb5ff6db7a0effbebd843b6e3f443e Mon Sep 17 00:00:00 2001 From: haorwen Date: Wed, 31 Dec 2025 00:41:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=9B=9E=E5=A4=8D?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E5=AE=9A=E4=BD=8D=E7=94=BB=E9=9D=A2=E5=A4=96?= =?UTF-8?q?=E7=9A=84=E6=B6=88=E6=81=AF=20(#289)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复回复无法定位画面外的消息 - Added a custom event to trigger scrolling to specific messages in the virtual message feed. - Enhanced the Reply component to dispatch the scroll event when messages are not in the DOM. - Improved user experience by highlighting messages briefly after scrolling to them. * fix: 修复删除消息报错 * chore: bump version to v0.9.45 --- package.json | 2 +- src/components/Message/Reply.tsx | 7 +++ src/components/Message/index.tsx | 13 +++-- .../chat/Layout/VirtualMessageFeed/index.tsx | 52 +++++++++++++++++++ 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 3c19f0cd..d62e56d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vocechat-web", - "version": "0.9.44", + "version": "0.9.45", "homepage": "https://voce.chat", "dependencies": { "@metamask/onboarding": "^1.0.1", diff --git a/src/components/Message/Reply.tsx b/src/components/Message/Reply.tsx index 8382d33e..eb0fccf7 100644 --- a/src/components/Message/Reply.tsx +++ b/src/components/Message/Reply.tsx @@ -102,6 +102,13 @@ const Reply: FC = ({ mid, interactive = true, context, to = 0 }) => msgEle.classList.remove(_class1); msgEle.classList.remove(_class2); }, 3000); + } else { + // 消息不在DOM中,触发自定义事件让虚拟列表滚动 + const feedId = `VOCECHAT_FEED_${context}_${to}`; + const feedEle = document.getElementById(feedId); + if (feedEle) { + feedEle.dispatchEvent(new CustomEvent('scrollToMessage', { detail: { mid: Number(mid) } })); + } } }; const defaultClass = `w-fit flex items-start flex-col md:flex-row p-2 bg-gray-100 dark:bg-gray-900 rounded-lg gap-2 mb-1`; diff --git a/src/components/Message/index.tsx b/src/components/Message/index.tsx index 0ac1bcbf..d2fe7a96 100644 --- a/src/components/Message/index.tsx +++ b/src/components/Message/index.tsx @@ -53,6 +53,12 @@ const Message: FC = ({ const currUser = useAppSelector((store) => store.users.byId[message?.from_uid || 0], shallowEqual); // 只订阅当前消息的reaction,而不是整个reactionMessageData const reactions = useAppSelector((store) => store.reactionMessage[mid], shallowEqual); + // 获取pinInfo中需要的用户信息 + const pinInfo = getPinInfo(mid); + const pinCreatorName = useAppSelector((store) => + pinInfo?.created_by ? store.users.byId[pinInfo.created_by]?.name : undefined, + shallowEqual + ); const toggleEditMessage = () => { setEdit((prev) => !prev); @@ -85,13 +91,6 @@ const Message: FC = ({ expires_in = 0, failed = false, } = message; - - // 获取pinInfo中需要的用户信息 - const pinInfo = getPinInfo(mid); - const pinCreatorName = useAppSelector((store) => - pinInfo?.created_by ? store.users.byId[pinInfo.created_by]?.name : undefined, - shallowEqual - ); // if (!message) return null; let timePrefix = null; diff --git a/src/routes/chat/Layout/VirtualMessageFeed/index.tsx b/src/routes/chat/Layout/VirtualMessageFeed/index.tsx index 825f90b3..208c3577 100644 --- a/src/routes/chat/Layout/VirtualMessageFeed/index.tsx +++ b/src/routes/chat/Layout/VirtualMessageFeed/index.tsx @@ -69,6 +69,58 @@ const VirtualMessageFeed = forwardRef(({ contex }, 500); }, [id]); + useEffect(() => { + const feedId = `VOCECHAT_FEED_${context}_${id}`; + const feedEle = document.getElementById(feedId); + + const handleScrollToMessage = (evt: CustomEvent) => { + const { mid } = evt.detail; + const index = mids.findIndex((m) => m === mid); + if (index !== -1 && vList.current) { + vList.current.scrollToIndex({ index, align: "center", behavior: "smooth" }); + setTimeout(() => { + const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); + if (msgEle) { + const _class1 = `md:dark:bg-gray-800`; + const _class2 = `md:bg-gray-100`; + msgEle.classList.add(_class1); + msgEle.classList.add(_class2); + setTimeout(() => { + msgEle.classList.remove(_class1); + msgEle.classList.remove(_class2); + }, 3000); + } + }, 500); + } else if (allMids.includes(mid)) { + setVisibleCount(allMids.length); + setTimeout(() => { + const idx = allMids.findIndex((m) => m === mid); + if (idx !== -1 && vList.current) { + vList.current.scrollToIndex({ index: idx, align: "center", behavior: "smooth" }); + setTimeout(() => { + const msgEle = document.querySelector(`[data-msg-mid='${mid}']`); + if (msgEle) { + const _class1 = `md:dark:bg-gray-800`; + const _class2 = `md:bg-gray-100`; + msgEle.classList.add(_class1); + msgEle.classList.add(_class2); + setTimeout(() => { + msgEle.classList.remove(_class1); + msgEle.classList.remove(_class2); + }, 3000); + } + }, 500); + } + }, 100); + } + }; + + feedEle?.addEventListener('scrollToMessage', handleScrollToMessage as EventListener); + return () => { + feedEle?.removeEventListener('scrollToMessage', handleScrollToMessage as EventListener); + }; + }, [context, id, mids, allMids]); + useEffect(() => { if (isSuccess && historyData) { if (historyData.length == 0) {