Skip to content

Commit 2afb8e9

Browse files
committed
fix: [MessageContainer] fix showBackBottom
1 parent d397746 commit 2afb8e9

File tree

3 files changed

+92
-85
lines changed

3 files changed

+92
-85
lines changed

demo/src/demo/Chat.tsx

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -188,51 +188,57 @@ export default () => {
188188
}
189189

190190
function handleRefresh() {
191-
prependMsgs([
192-
{
193-
_id: '1111',
194-
type: 'text',
195-
content: { text: '11111Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
196-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
197-
},
198-
{
199-
_id: '2222',
200-
type: 'text',
201-
content: { text: '22222 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
202-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
203-
},
204-
{
205-
_id: '3333',
206-
type: 'text',
207-
content: { text: '333 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
208-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
209-
},
210-
{
211-
_id: '4444',
212-
type: 'text',
213-
content: { text: '444 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
214-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
215-
},
216-
{
217-
_id: '5555',
218-
type: 'text',
219-
content: { text: '555 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
220-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
221-
},
222-
{
223-
_id: '6666',
224-
type: 'text',
225-
content: { text: '666 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
226-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
227-
},
228-
{
229-
_id: '7777',
230-
type: 'text',
231-
content: { text: '777 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
232-
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
233-
},
234-
]);
235-
return Promise.resolve({});
191+
return new Promise((resolve) => {
192+
setTimeout(() => {
193+
const now = Date.now();
194+
195+
prependMsgs([
196+
{
197+
_id: now + '1111',
198+
type: 'text',
199+
content: { text: '11111Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
200+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
201+
},
202+
{
203+
_id: now + '2222',
204+
type: 'text',
205+
content: { text: '22222 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
206+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
207+
},
208+
{
209+
_id: now + '3333',
210+
type: 'text',
211+
content: { text: '333 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
212+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
213+
},
214+
{
215+
_id: now + '4444',
216+
type: 'text',
217+
content: { text: '444 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
218+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
219+
},
220+
{
221+
_id: now + '5555',
222+
type: 'text',
223+
content: { text: '555 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
224+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
225+
},
226+
{
227+
_id: now + '6666',
228+
type: 'text',
229+
content: { text: '666 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
230+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
231+
},
232+
{
233+
_id: now + '7777',
234+
type: 'text',
235+
content: { text: '777 Hi,我是你的专属智能助理小蜜,有问题请随时找我哦~' },
236+
user: { avatar: '//gw.alicdn.com/tfs/TB1DYHLwMHqK1RjSZFEXXcGMXXa-56-62.svg' },
237+
},
238+
]);
239+
resolve({});
240+
}, 800);
241+
});
236242
}
237243

238244
function handleToolbarClick(item: ToolbarItemProps) {

src/components/MessageContainer/index.tsx

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { PullToRefresh, PullToRefreshHandle, ScrollToEndOptions } from '../PullT
44
import { Message, MessageProps } from '../Message';
55
import { BackBottom } from '../BackBottom';
66
import canUse from '../../utils/canUse';
7+
import throttle from '../../utils/throttle';
78
import getToBottom from '../../utils/getToBottom';
89

910
const listenerOpts = canUse('passiveListener') ? { passive: true } : false;
@@ -22,8 +23,8 @@ export interface MessageContainerHandle {
2223
scrollToEnd: (options?: ScrollToEndOptions) => void;
2324
}
2425

25-
function getMaxOffsetHeight(wrapper: HTMLElement) {
26-
return wrapper.offsetHeight * 1.5;
26+
function isNearBottom(el: HTMLElement) {
27+
return getToBottom(el) < el.offsetHeight * 1.5;
2728
}
2829

2930
export const MessageContainer = React.forwardRef<MessageContainerHandle, MessageContainerProps>(
@@ -42,7 +43,6 @@ export const MessageContainer = React.forwardRef<MessageContainerHandle, Message
4243
const messagesRef = useRef<HTMLDivElement>(null);
4344
const scrollerRef = useRef<PullToRefreshHandle>(null);
4445
const bottomRef = useRef<HTMLDivElement>(null);
45-
const isTouching = useRef(false);
4646
const lastMessage = messages[messages.length - 1];
4747

4848
const scrollToEnd = useCallback((opts?: ScrollToEndOptions) => {
@@ -57,17 +57,36 @@ export const MessageContainer = React.forwardRef<MessageContainerHandle, Message
5757
setNewCount(0);
5858
};
5959

60+
const checkShowBottomRef = useRef(
61+
throttle((el: HTMLElement) => {
62+
if (isNearBottom(el)) {
63+
setShowBackBottom(false);
64+
setNewCount(0);
65+
} else {
66+
setShowBackBottom(true);
67+
}
68+
}),
69+
);
70+
71+
const handleScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => {
72+
checkShowBottomRef.current(e.target);
73+
74+
if (onScroll) {
75+
onScroll(e);
76+
}
77+
};
78+
6079
useEffect(() => {
6180
const scroller = scrollerRef.current;
6281
const wrapper = scroller && scroller.wrapperRef.current;
6382

64-
if (!wrapper) {
83+
if (!wrapper || !lastMessage) {
6584
return;
6685
}
6786

6887
if (lastMessage.position === 'right') {
6988
scrollToEnd();
70-
} else if (getToBottom(wrapper) < getMaxOffsetHeight(wrapper)) {
89+
} else if (isNearBottom(wrapper)) {
7190
const animated = !!wrapper.scrollTop;
7291
scrollToEnd({ animated });
7392
} else {
@@ -76,38 +95,6 @@ export const MessageContainer = React.forwardRef<MessageContainerHandle, Message
7695
}
7796
}, [lastMessage, scrollToEnd]);
7897

79-
useEffect(() => {
80-
const scroller = scrollerRef.current;
81-
const wrapper = scroller && scroller.wrapperRef.current;
82-
83-
if (!wrapper) {
84-
return;
85-
}
86-
87-
const options = {
88-
root: wrapper,
89-
rootMargin: `0px 0px ${getMaxOffsetHeight(wrapper)}px 0px`,
90-
threshold: 1.0,
91-
};
92-
93-
const observer = new IntersectionObserver(([entry]) => {
94-
if (!isTouching.current) {
95-
if (entry.isIntersecting) {
96-
setShowBackBottom(false);
97-
setNewCount(0);
98-
} else {
99-
setShowBackBottom(true);
100-
}
101-
}
102-
}, options);
103-
104-
observer.observe(bottomRef.current!);
105-
106-
return () => {
107-
observer.disconnect();
108-
};
109-
}, []);
110-
11198
useEffect(() => {
11299
const wrapper = messagesRef.current!;
113100

@@ -117,7 +104,6 @@ export const MessageContainer = React.forwardRef<MessageContainerHandle, Message
117104
function reset() {
118105
needBlur = false;
119106
startY = 0;
120-
isTouching.current = false;
121107
}
122108

123109
function touchStart(e: TouchEvent) {
@@ -126,7 +112,6 @@ export const MessageContainer = React.forwardRef<MessageContainerHandle, Message
126112
needBlur = true;
127113
startY = e.touches[0].clientY;
128114
}
129-
isTouching.current = true;
130115
}
131116

132117
function touchMove(e: TouchEvent) {
@@ -156,7 +141,7 @@ export const MessageContainer = React.forwardRef<MessageContainerHandle, Message
156141
{renderBeforeMessageList && renderBeforeMessageList()}
157142
<PullToRefresh
158143
onRefresh={onRefresh}
159-
onScroll={onScroll}
144+
onScroll={handleScroll}
160145
loadMoreText={loadMoreText}
161146
ref={scrollerRef}
162147
>

src/utils/throttle.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export default function throttle(fn: Function, delay = 300) {
2+
let ready = true;
3+
4+
return (...args: any) => {
5+
if (!ready) {
6+
return;
7+
}
8+
9+
ready = false;
10+
fn(...args);
11+
12+
setTimeout(() => {
13+
ready = true;
14+
}, delay);
15+
};
16+
}

0 commit comments

Comments
 (0)