【发布时间】:2017-06-17 03:28:18
【问题描述】:
我想知道在 React 应用中实现布局的最佳方法是什么。
基础知识
假设我们想要在简单的网格中布置 4 个组件。最基本的方法是这样的。
<svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
<A color="red" x={0} y={0} width={width/2} height={height/2} />
<B color="blue" x={width/2} y={0} width={width/2} height={height/2} />
<B color="green" x={0} y={height/2} width={width/2} height={height/2} />
<A color="yellow" x={width/2} y={height/2} width={width/2} height={height/2} />
</svg>
http://codepen.io/anon/pen/OWOXvV?editors=0010
它可以正常工作,但是键入显式大小值容易出错并且对开发人员不友好。如果我们可以改用百分比值 (0 - 1) 会怎样?
简单容器
const Container = ({x, y, width, height, children}) => {
return (
<g transform={`translate(${x}, ${y})`}>
{React.Children.map(children, (child) => React.cloneElement(child, { // this creates a copy
x: child.props.x * width,
y: child.props.y * height,
width: child.props.width * width,
height: child.props.height * height
}))}
</g>
);
};
<svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
<Container width={width} height={height}>{/* one root container is given real pixel size */}
<Container width={1/2}>{/* it's children recursively use 0-1 coordinates */}
<A color="red" height={1/2} />
<B color="green" y={1/2} height={1/2} />
</Container>
<Container x={1/2} width={1/2}>
<B color="blue" height={1/2} />
<A color="yellow" y={1/2} height={1/2} />
</Container>
</Container>
</svg>
http://codepen.io/anon/pen/PWEmVd?editors=0010
在这种情况下,我们将允许 Container 组件将其子组件的相对值映射到实际像素值。它更容易使用。
布局容器
另一个步骤是创建布局容器 f.e. HContainer 只是水平放置其子级。
const HContainer = ({ x, y, width, height, children }) => {
const c = React.Children.toArray(children);
const ratio = width / c.reduce((sum, child) => (sum + child.props.width), 0);
return (
<g transform={`translate(${x}, ${y})`}>
{c.reduce((result, child) => {
const width = child.props.width * ratio;
result.children.push(React.cloneElement(child, { // this creates a copy
x: result.x,
y: 0,
width,
height
}));
result.x += width;
return result;
}, { x: 0, children: [] }).children}
</g>
);
};
<svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
<HContainer width={width} height={height}>{/* one root container is given real pixel size */}
<Container width={1/4}>{/* it's children recursively use 0-1 coordinates */}
<A color="red" height={1/2} />
<B color="green" y={1/2} height={1/2} />
</Container>
<VContainer width={3/4}>
<B color="blue" />
<A color="yellow" />
<HContainer height={1/2}>
<B color="pink" />
<A color="violet" width={3} />
<B color="#333" />
</HContainer>
</VContainer>
</HContainer>
</svg>
http://codepen.io/anon/pen/pRpwBe?editors=0010
响应式组件
假设我们希望在宽度或高度低于某个值时移除一些组件。你可能会使用这样的条件渲染。
const MinWidth = ({ children, width, minWidth, ... others }) => {
return minWidth > width ? null : <Container width={width} {... others }>{ children }</Container>;
};
<svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
<HContainer width={width} height={height}>{/* one root container is given real pixel size */}
<Container width={1/4}>{/* it's children recursively use 0-1 coordinates */}
<A color="red" height={1/2} />
<B color="green" y={1/2} height={1/2} />
</Container>
<VContainer width={3/4}>
<B color="blue" />
<MinHeight height={1} minHeight={80}>
<A color="yellow" />
</MinHeight>
<HContainer height={1/2}>
<B color="pink" />
<A color="violet" width={3} />
<MinWidth width={1} minWidth={60}>
<B color="#333" />
</MinWidth>
</HContainer>
</VContainer>
</HContainer>
</svg>
http://codepen.io/anon/pen/dNJZGd?editors=0010
但这会在过去跳过组件的地方留下空白。布局容器应该能够扩展渲染组件以填充可用空间。
响应式布局
这是棘手的部分。我看不到其他方法来查看组件是否会呈现,而是实例化并呈现它(它是子组件)。然后,如果我在可用空间内放置 3 个子组件并发现第 4 个不应该被渲染,我将不得不重新渲染之前的 3 个。感觉就像打破了 React 流程。
有人有什么想法吗?
【问题讨论】:
-
因为我试图了解 React 组件应如何正确管理其子级。还有一些渲染目标不支持 CSS。
-
您正在尝试实现 2008 年的 Web 开发。我们将其命名为“表格布局”。))))
-
@m1gu3l 用组件内联编写你的 CSS 将帮助你沿着 react 的父子关系管理你的 CSS。如果您遵循最佳实践,孩子的不应过多地影响父母的。现在,如果您出于某种原因(可能是由于某些技术需求)对 css-less react 有特定的需求,那么我们当然可以与您合作。否则,“react without css”只是一个不必要的反模式。@DenTemple ,我更想弄清楚应该如何在 React 本身中完成这样的事情。我知道如何用 CSS 做到这一点,它对 flexbox 来说相当简单,但是 - flexbox 在 svg 和 f.e. 上不起作用。 canvas 根本不支持 css。终于,一个 js 开发人员用命令式语言实现了布局,哦,等等,你用 svg 代替了数学...:P 谢谢!
标签: javascript reactjs layout responsive