如何控制MUI List自动滚动,解决聊天场景消息被输入框遮挡问题
实现方案
1. 修复布局溢出问题
外层采用flex垂直布局占满整个视口,让中间聊天区域自动填充剩余高度,List组件限制滚动范围,避免内容溢出到输入框区域:
- 最外层容器添加flex布局样式,固定高度为100vh,禁止整体溢出
- 包裹标题和List的中间容器设置
flex:1,自动占满头部和底部输入框之间的空间 - List组件添加纵向滚动属性,内容超出高度时自动出现滚动条
对应代码修改点:
// 最外层div修改 <div style={{ display: 'flex', flexDirection: 'column', height: '100vh', overflow: 'hidden' }}> <CssBaseline /> {/* 中间容器修改 */} <div className={classes.section} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> <Typography variant="h5" gutterBottom component="div" sx={{ p: 2, pb: 0 }}> Inbox </Typography> {/* List组件修改 */} <List sx={{ mb: 2, flex: 1, overflowY: 'auto', overscrollBehavior: 'contain' // 避免滚动时触发父容器回弹 }} > {/* 原有ListItem逻辑不变 */} </List> </div> {/* 底部输入框原有逻辑不变 */} </div>
如果需要固定List的最大高度,只需要把List的flex:1替换为maxHeight: 'calc(100vh - 180px)'即可,数值根据自身头部、底部的实际高度调整。
2. 实现新消息自动滚动到底部
配合React的ref和副作用监听,每次消息列表更新时自动滚动到最底部:
- 引入对应Hook:
import { useRef, useEffect } from 'react'
- 组件内定义List的ref和滚动副作用:
const listRef = useRef(null) // 监听messages变化,自动滚动到底部 useEffect(() => { listRef.current?.scrollTo(0, listRef.current.scrollHeight) }, [messages])
- 将ref绑定到List组件:
<List ref={listRef} {/* 其他原有属性 */}>
修改后完整代码
import { useRef, useEffect } from 'react' // 其他原有导入不变 // 组件内部逻辑 const YourChatComponent = () => { // 原有state、函数逻辑不变 const listRef = useRef(null) useEffect(() => { listRef.current?.scrollTo(0, listRef.current.scrollHeight) }, [messages]) return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100vh', overflow: 'hidden' }}> <CssBaseline /> <div className={classes.section} style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}> <Typography variant="h5" gutterBottom component="div" sx={{ p: 2, pb: 0 }}> Inbox </Typography> <List ref={listRef} sx={{ mb: 2, flex: 1, overflowY: 'auto', overscrollBehavior: 'contain' }} > {messages.map( (item) => ( <ListItem button key ={item.id} ref={messageRef}> <ListItemAvatar> <Avatar alt="Profile Picture" /> </ListItemAvatar> <ListItemText primary={item.content} secondary={item.sender} /> </ListItem> ))} </List> </div> <paperClasses className= {classes.footer}> <div style={{marginLeft: 'calc(1%)', backgroundColor: '#f1f3f4', borderRadius: '25px'}}> <Controls.Input name = "message" label= "Send message" value= {message} onChange={onChangeHandler} InputProps={{ disableUnderline: true, }} /> <Controls.Button onClick={sendMessage} text="Send" /> </div> </paperClasses> </div> ); }
内容的提问来源于stack exchange,提问作者DrDoggo。
相关产品推荐
相关产品推荐

