fix: 修复回复无法定位画面外的消息 (#289)

* 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
This commit is contained in:
haorwen
2025-12-31 00:41:40 +08:00
committed by GitHub
parent 7f14b4b65e
commit 5897f3304a
4 changed files with 66 additions and 8 deletions
+1 -1
View File
@@ -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",
+7
View File
@@ -102,6 +102,13 @@ const Reply: FC<ReplyProps> = ({ 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`;
+6 -7
View File
@@ -53,6 +53,12 @@ const Message: FC<IProps> = ({
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<IProps> = ({
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;
@@ -69,6 +69,58 @@ const VirtualMessageFeed = forwardRef<VirtualMessageFeedHandle, Props>(({ 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<HTMLDivElement>(`[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<HTMLDivElement>(`[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) {