MUI DesktopDatePicker在iframe中打开时触发父页面滚动至顶部问题求助
解决iframe中MUI DesktopDatePicker点击触发父页面滚动的问题
问题背景
在iframe内使用MUI DesktopDatePicker组件时,点击打开日期选择器的按钮会导致父页面自动滚动至顶部。尝试通过强制保持按钮聚焦来修复时,又出现了点击组件外部后页面滚动回聚焦元素的新问题。
原实现代码片段:
useEffect(() => { if (datePicker.current) { const blurPreventButton = datePicker.current.parentElement?.children[1].children[0]; if (blurPreventButton) { blurPreventButton.id = 'openDatePickerButton'; iframeBlurManipulation(); } } }, []); export default function iframeBlurManipulation() { const button = document.querySelector('#openDatePickerButton'); if (button) { button.addEventListener('blur', (event) => { event.target.focus(); }); } }
可行解决方案
方案1:阻止打开按钮聚焦时的滚动行为
问题核心是按钮聚焦时触发了跨iframe的滚动同步,直接给按钮添加preventScrollOnFocus属性即可解决:
<DesktopDatePicker className="capitalize-text" value={selectedDate} autoFocus={false} slots={{ day: ServerDay, }} inputRef={datePicker} onChange={handleDateChange} shouldDisableDate={shouldDisableDate} minDate={dayjs(firstValidDate)} slotProps={{ popper: { disablePortal: true, autoFocus: false, }, // 给打开按钮添加阻止滚动的属性 openPickerButton: { preventScrollOnFocus: true, }, }} maxDate={dayjs(Object.values(departureDates).pop() || '')} />
添加后,移除之前的iframeBlurManipulation函数和对应的useEffect逻辑即可,无需强制保持按钮聚焦。
方案2:拦截iframe内的滚动事件传播
如果方案1不生效,可以通过监听iframe内部的滚动事件,阻止其冒泡到父页面:
useEffect(() => { const stopScrollPropagation = (e) => e.stopPropagation(); window.addEventListener('scroll', stopScrollPropagation); return () => window.removeEventListener('scroll', stopScrollPropagation); }, []);
方案3:自定义打开按钮逻辑
完全接管打开按钮的点击行为,避免默认聚焦触发的滚动:
const [isPickerOpen, setIsPickerOpen] = useState(false); const handleOpenPicker = (e) => { e.preventDefault(); // 阻止默认聚焦行为 setIsPickerOpen(true); }; <DesktopDatePicker className="capitalize-text" value={selectedDate} autoFocus={false} open={isPickerOpen} onClose={() => setIsPickerOpen(false)} slots={{ day: ServerDay, openPickerButton: () => ( <button onClick={handleOpenPicker} type="button"> 选择日期 </button> ), }} inputRef={datePicker} onChange={handleDateChange} shouldDisableDate={shouldDisableDate} minDate={dayjs(firstValidDate)} slotProps={{ popper: { disablePortal: true, autoFocus: false, }, }} maxDate={dayjs(Object.values(departureDates).pop() || '')} />
以上方案均可解决原问题,同时避免点击外部页面滚动回聚焦元素的副作用。
内容的提问来源于stack exchange,提问作者Rolandas Dovydėnas
相关产品推荐
相关产品推荐

