在React中使用React Foldable Layout处理折叠区域样式,核心是结合组件库的区域划分能力与React的样式方案(如CSS Modules、Styled Components),针对“折叠/展开”状态、“折痕避让”、“区域差异化样式”三大场景设计解决方案。以下是具体实现步骤与示例:
一、基础准备:理解React Foldable Layout的核心组件
React Foldable Layout通过两个核心组件实现区域管理,需先明确其作用:
<FoldableProvider>:根容器,负责检测折叠屏状态(依赖底层API或降级方案),并将状态传递给子组件;<FoldableRegion>:区域容器,通过position属性指定区域位置(如left/main/right),支持根据折叠状态显示/隐藏。
安装依赖(若未安装):
npm install react-foldable-layout --save
二、场景1:根据折叠状态切换全局样式
通过FoldableProvider提供的isFolded状态,动态添加全局类名,实现“折叠单栏/展开双栏”的样式切换。
1. 组件结构与状态获取
import { FoldableProvider, FoldableRegion, useFoldableContext } from 'react-foldable-layout';
// 子组件:通过Context获取折叠状态
const AppLayout = () => {
// 从Context中获取折叠状态(isFolded)和区域信息(segments)
const { isFolded } = useFoldableContext();
return (
<div className={`app-container ${isFolded ? 'folded' : 'unfolded'}`}>
{/* 左侧区域:展开时显示,折叠时隐藏 */}
<FoldableRegion position="left" fallback={null}>
<Sidebar />
</FoldableRegion>
{/* 主区域:始终显示 */}
<FoldableRegion position="main">
<MainContent />
</FoldableRegion>
</div>
);
};
// 根组件:包裹FoldableProvider
const App = () => {
return (
<FoldableProvider>
<AppLayout />
</FoldableProvider>
);
};
2. 全局样式设计(CSS Modules示例)
创建AppLayout.module.css,针对folded/unfolded类名编写差异化样式:
/* 容器基础样式 */
.app-container {
display: flex;
height: 100vh;
overflow: hidden;
transition: all 0.3s ease; /* 状态切换时平滑过渡 */
}
/* 折叠状态:仅显示主区域,隐藏左侧 */
.folded {
.sidebar {
display: none;
}
.main-content {
width: 100%;
padding: 16px;
}
}
/* 展开状态:左右分栏 */
.unfolded {
.sidebar {
width: 280px; /* 固定宽度或使用视口单位 */
background: #f5f5f5;
border-right: 1px solid #eee;
padding: 16px;
overflow-y: auto;
}
.main-content {
flex: 1; /* 占满剩余宽度 */
padding: 24px;
overflow-y: auto;
}
}
3. 组件引入样式
import styles from './AppLayout.module.css';
const AppLayout = () => {
const { isFolded } = useFoldableContext();
return (
<div className={`${styles['app-container']} ${isFolded ? styles.folded : styles.unfolded}`}>
<FoldableRegion position="left" fallback={null}>
<div className={styles.sidebar}>
<Sidebar />
</div>
</FoldableRegion>
<FoldableRegion position="main">
<div className={styles['main-content']}>
<MainContent />
</div>
</FoldableRegion>
</div>
);
};
三、场景2:折痕避让(避免内容被折痕遮挡)
React Foldable Layout的useFoldableContext会返回foldPosition(折痕位置),可基于此动态调整区域内元素的内边距,避开折痕。
1. 折痕位置获取与样式应用
const MainContent = () => {
const { isFolded, foldPosition, orientation } = useFoldableContext();
// 计算安全内边距:仅在展开且水平折叠时生效
const safePadding = isFolded
? 16 // 折叠时默认内边距
: orientation === 'horizontal'
? Math.max(16, window.innerWidth - foldPosition - 16) // 右侧区域避开折痕
: 16;
// 动态样式:通过inline style应用安全内边距
const contentStyle = {
paddingLeft: orientation === 'horizontal' && !isFolded ? `${safePadding}px` : '16px',
paddingRight: '16px',
};
return (
<div style={contentStyle}>
<h1>核心内容区</h1>
<p>折痕位置:{foldPosition}px,当前内边距:{contentStyle.paddingLeft}</p>
{/* 其他内容 */}
</div>
);
};
2. 优化:使用CSS变量传递折痕位置
若需在CSS中直接使用foldPosition,可通过style属性将其注入为CSS变量:
const AppLayout = () => {
const { foldPosition, isFolded } = useFoldableContext();
return (
<div
className={`${styles['app-container']} ${isFolded ? styles.folded : styles.unfolded}`}
style={
{
'--fold-position': `${foldPosition}px`, // 注入CSS变量
}}
>
{/* 区域内容 */}
</div>
);
};
在CSS中使用变量:
/* 展开状态下的主区域 */
.unfolded {
.main-content {
/* 利用CSS变量计算内边距,避开折痕 */
padding-left: max(16px, calc(100vw - var(--fold-position) - 16px));
}
}
四、场景3:区域内组件的响应式样式
针对区域内的子组件(如卡片、列表),需根据区域尺寸动态调整样式(如卡片列数、字体大小)。可结合useFoldableContext的segments(区域尺寸数组)实现。
1. 区域尺寸获取与组件样式调整
const ProductList = () => {
const { segments, isFolded } = useFoldableContext();
// 获取主区域尺寸(segments[1]为展开时的主区域,segments[0]为折叠时的唯一区域)
const mainRegionSize = isFolded
? segments[0]
: segments.find(seg => seg.position === 'main') || segments[1];
// 根据区域宽度决定卡片列数
const getColumnCount = () => {
if (mainRegionSize.width < 500) return 1; // 窄区域:1列
if (mainRegionSize.width < 800) return 2; // 中等宽度:2列
return 3; // 宽区域:3列
};
return (
<div
className="product-list"
style={
{
display: 'grid',
gridTemplateColumns: `repeat(${getColumnCount()}, 1fr)`,
gap: '16px',
}}
>
{/* 产品卡片 */}
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
};
五、场景4:使用Styled Components实现动态样式
若项目使用Styled Components,可直接将折叠状态作为props传递给样式组件,实现更灵活的动态样式。
1. 定义样式组件
import styled from 'styled-components';
// 动态容器组件:接收isFolded作为props
const StyledContainer = styled.div`
display: flex;
height: 100vh;
overflow: hidden;
transition: all 0.3s ease;
/* 折叠状态样式 */
${props => props.isFolded && `
.sidebar {
display: none;
}
.main-content {
width: 100%;
padding: 16px;
}
`}
/* 展开状态样式 */
${props => !props.isFolded && `
.sidebar {
width: 280px;
background: #f5f5f5;
border-right: 1px solid #eee;
padding: 16px;
}
.main-content {
flex: 1;
padding: 24px;
}
`}
`;
// 动态主内容组件:接收foldPosition作为props
const StyledMainContent = styled.div`
overflow-y: auto;
padding-right: 16px;
/* 折痕避让 */
${props => !props.isFolded && `
padding-left: max(16px, calc(100vw - ${props.foldPosition}px - 16px));
`}
`;
2. 组件中使用
const AppLayout = () => {
const { isFolded, foldPosition } = useFoldableContext();
return (
<StyledContainer isFolded={isFolded}>
<FoldableRegion position="left" fallback={null}>
<div className="sidebar">
<Sidebar />
</div>
</FoldableRegion>
<FoldableRegion position="main">
<StyledMainContent isFolded={isFolded} foldPosition={foldPosition}>
<MainContent />
</StyledMainContent>
</FoldableRegion>
</StyledContainer>
);
};
六、常见问题与解决方案
1. 区域切换时样式抖动
问题:折叠/展开切换时,组件样式突变导致抖动。
解决:添加transition过渡动画(如前文在.app-container中添加transition: all 0.3s ease),并确保DOM结构稳定(避免频繁添加/删除元素,优先用display: none控制显示)。
2. 折痕位置计算不准确
问题:foldPosition与真实设备折痕位置偏差。
解决:结合设备厂商API修正(如三星的window.screen.getFoldInfo()),在FoldableProvider初始化时传入自定义状态检测逻辑:
const customGetState = () => {
// 三星设备自定义折痕位置
if (window.screen?.getFoldInfo) {
const foldInfo = window.screen.getFoldInfo();
return {
isFolded: foldInfo.state === 'folded',
foldPosition: foldInfo.x,
orientation: 'horizontal',
};
}
// 默认逻辑
return defaultGetState();
};
const App = () => {
return (
<FoldableProvider getState={customGetState}>
<AppLayout />
</FoldableProvider>
);
};
3. 非折叠屏设备样式异常
问题:在普通手机/电脑上,unfolded样式仍生效。
解决:通过useFoldableContext的isFoldableDevice判断是否为折叠屏设备,非折叠屏强制使用单栏样式:
const AppLayout = () => {
const { isFoldableDevice, isFolded } = useFoldableContext();
// 非折叠屏设备强制视为“折叠状态”
const isSingleColumn = !isFoldableDevice || isFolded;
return (
<div className={`${styles['app-container']} ${isSingleColumn ? styles.folded : styles.unfolded}`}>
{/* 内容 */}
</div>
);
};
总结
在React中使用React Foldable Layout处理折叠区域样式,核心思路是:
- 依赖Context获取状态:通过
useFoldableContext获取isFolded(折叠状态)、foldPosition(折痕位置)等关键信息; - 动态样式切换:结合CSS类名、inline style或Styled Components,根据状态编写差异化样式;
- 细节优化:重点处理折痕避让、过渡动画和非折叠屏兼容,确保体验一致性。
通过以上方法,可高效实现折叠屏H5的样式适配,兼顾灵活性与兼容性。