布局系统
OpenTUI 使用 Yoga 布局引擎提供类似 CSS Flexbox 的能力,用于响应式终端布局。你可以创建适应终端大小变化的复杂动态界面。
Flexbox 基础
布局系统支持标准的 flexbox 属性:
import { BoxRenderable, createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
const container = new BoxRenderable(renderer, {
id: "container",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
height: 10,
})
const leftPanel = new BoxRenderable(renderer, {
id: "left",
flexGrow: 1,
height: 10,
backgroundColor: "#444",
})
const rightPanel = new BoxRenderable(renderer, {
id: "right",
width: 20,
height: 10,
backgroundColor: "#666",
})
container.add(leftPanel)
container.add(rightPanel)
renderer.root.add(container)
Flex 方向
控制子元素的方向:
// 垂直布局(默认)
{
flexDirection: "column"
}
// 水平布局
{
flexDirection: "row"
}
// 反向
{
flexDirection: "row-reverse"
}
{
flexDirection: "column-reverse"
}
主轴对齐(Justify Content)
沿主轴对齐子元素:
{
justifyContent: "flex-start"
} // 起点对齐
{
justifyContent: "flex-end"
} // 终点对齐
{
justifyContent: "center"
} // 居中对齐
{
justifyContent: "space-between"
} // 均匀间距,两端无间隙
{
justifyContent: "space-around"
} // 均匀间距,两端有间隙
{
justifyContent: "space-evenly"
} // 完全均匀间距
交叉轴对齐(Align Items)
沿交叉轴对齐子元素:
{
alignItems: "flex-start"
} // 起点对齐
{
alignItems: "flex-end"
} // 终点对齐
{
alignItems: "center"
} // 交叉轴居中
{
alignItems: "stretch"
} // 拉伸填充(默认)
{
alignItems: "baseline"
} // 基线对齐
大小调整
固定大小
{
width: 30, // 固定宽度(字符数)
height: 10, // 固定高度(行数)
}
百分比大小
{
width: "100%", // 父元素的全宽
height: "50%", // 父元素高度的一半
}
Flex 增长和收缩
{
flexGrow: 1, // 占用可用空间
flexShrink: 0, // 不收缩到内容大小以下
flexBasis: 100, // flex 调整前的初始大小
}
定位
相对定位(默认)
元素在布局中正常流动:
{
position: "relative",
}
绝对定位
相对于父元素定位元素:
{
position: "absolute",
left: 10,
top: 5,
right: 10,
bottom: 5,
}
内边距和外边距
{
// 统一内边距
padding: 2,
// 按轴设置
paddingX: 4,
paddingY: 2,
// 单独设置各边
paddingTop: 1,
paddingRight: 2,
paddingBottom: 1,
paddingLeft: 2,
// 外边距同理
margin: 1,
marginX: 3,
marginY: 1,
marginTop: 1,
marginRight: 2,
marginBottom: 1,
marginLeft: 2,
}
使用 Constructs
相同的布局属性也适用于声明式 API:
import { Box, Text } from "@opentui/core"
renderer.root.add(
Box(
{
flexDirection: "row",
width: "100%",
height: 10,
},
Box(
{
flexGrow: 1,
backgroundColor: "#333",
padding: 1,
},
Text({ content: "Left Panel" }),
),
Box(
{
width: 20,
backgroundColor: "#555",
padding: 1,
},
Text({ content: "Right Panel" }),
),
),
)
响应式布局
监听终端大小调整事件以创建响应式布局:
const renderer = await createCliRenderer()
renderer.on("resize", (width, height) => {
// 根据新尺寸更新布局
if (width < 80) {
container.flexDirection = "column"
} else {
container.flexDirection = "row"
}
})