没有 CSS 的响应式布局

Posted

技术标签:

【中文标题】没有 CSS 的响应式布局【英文标题】:React responsive layout without CSS 【发布时间】: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 谢谢! 【参考方案1】:

在内联样式中使用 flexbox。从代码的外观来看,您已经在使用内联样式。 Here is some help

【讨论】:

Flexbox 是 CSS 模块,它不适用于 React 组件 - 仅适用于它们的 html DOM 表示。这就是我在示例中使用 SVG 的原因,SVG 不支持 Flexbox。【参考方案2】:

您可以使用react-flexbox-grid 轻松布局组件,而无需接触任何 CSS。

const Grid, Row, Col = require('react-flexbox-grid');

const App = React.createClass(
  render() 
    return (
      <Grid>
        <Row>
          <Col xs=6 md=3>Hello, world!</Col>
        </Row>
      </Grid>
    );
  
);

【讨论】:

这实际上是在下面使用CSS Flexbox。

以上是关于没有 CSS 的响应式布局的主要内容,如果未能解决你的问题,请参考以下文章

响应式布局简明示例

H5响应式布局 响应式图片 响应式布局网站怎么写?

一行 CSS 代码实现响应式布局 – 使用 Grid 实现的响应式布局

CSS3响应式布局(媒体查询@media)

CSS3响应式布局(媒体查询@media)

css高级篇 (布局:静态流式弹性自适应响应式)