react实战 : 用矩阵思想做一个自适应布局容器组件

需求是这样的。

  • 有一个需要显示若干方块型元素的小区域
  • 数量比较少的时候显示一排
  • 数量比较多的时候显示两排

用 grid 不好,因为当数量为奇数的时候需要两排里面的元素都乖乖的居中显示。

用 flex 的话,直接写需要写很多判断,因为行数不同的时候页面结构也会不同。

所以,我想到用二维数组(矩阵)来表示在什么时候想怎样显示。

 

上代码。

// 波浪效果测试

import React from 'react'

import Styles from './index.less'

import Wave from '../wave/index.js'
import { Flex } from 'antd-mobile'

class WaveContainer extends React.Component {
  constructor(props){
    super(props)
    this.state = {
    }
  }

  render(){
    console.log(this.props.dataBar)

    const baseFlex = {
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    }
    const theStyle = {
      main:{
        ...baseFlex,
        width:'17.552vw',
        height:'10.521vw',
        color:"#fff"
      },
      tem:{
        ...baseFlex,
        flex:"auto",
        color:'#fff'
      },
      shellA:{
        ...baseFlex,
        width:'100%',
        height:'100%'
      },
      shellB:{
        ...baseFlex,
        width:'100%',
        height:'50%'
      }
    }

    const dataBar = this.props.dataBar

    const Container = ((dataBar) => {

      const flexMatrix = [
        [0,0],
        [1,0],
        [2,0],
        [3,0],
        [2,2],
        [3,2],
        [3,3],
        [4,3],
        [4,4],
        [5,4],
        [5,5],
        [6,5],
        [6,6]
      ]

      const sData = dataBar.data.sData
      const length = sData.length

      const matrix = flexMatrix[length] ? flexMatrix[length] : flexMatrix[12]

      if (matrix[0] === 0) {
        return ""
      }

      let temShell, temA, temB 

      temA = sData.slice(0, matrix[0]).map((item, index) => 
        <div style={theStyle.tem} key={index.toString()}> <Wave data={item} /> </div>
      );

      if (matrix[1] === 0) {
        temB = ""
      } else {
        temB = sData.slice(matrix[0], (matrix[0] + matrix[1])).map((item, index) => 
          <div style={theStyle.tem} key={index.toString()}> <Wave data={item} /> </div>
        );
      }

      if (matrix[1] === 0) {
        temShell = <div style={theStyle.shellA} > {temA} </div>
      } else {
        temShell = [0,0].map((item, index) => 
          <div style={theStyle.shellB} key={"temShell" + index.toString()}> {index === 0 ? temA : temB} </div>
        );

        theStyle.main.flexWrap = "wrap"
      }

      console.log(temShell)
      
      return temShell
    })(dataBar)

    return (
      <div style={theStyle.main}>
        {/* <Wave /> */}
        { Container }
      </div>
    );
  }
}

export default WaveContainer

 

稍微解释一下。

  • 用展开运算符使样式更简洁。
  • flexMatrix 就是记录数据的矩阵。
  • temA, temB 是放一行元素的容器。
  • temShell 是放 temA, temB 的容器。
  • theStyle.main.flexWrap = "wrap" 让元素可以正常换行。
  • slice 的作用是分割数据对象,一行只渲染一行需要的那些数据。
  • [0,0] 是因为需要两行,所以用有两个元素的数组,用 map 输出 JSX。

 

然后是从页面传入的数据的代码。

render(){
    const dataBar = {
         data:{
            sData:[
              { name: 'a', data: 55, color:'rgb(79,239,223)' },
              { name: 'b', data: 5, color:'rgb(79,239,223)'},
              { name: 'c', data: 36, color:'rgb(79,239,223)'},
              { name: 'd', data: 476, color:'rgb(87,207,30)'},
              { name: 'e', data: 226, color:'rgb(79,239,223)'},
              { name: 'f', data: 273, color:'rgb(251,211,36)'}
            ]
          }
    }

    return (
      <div className={Styles.main}>
        <WaveContainer dataBar={dataBar} />
      </div>
    );
  }

其实和他也没什么关系。因为直接把对象传入了更里面的元素。

 

以上。

 

 

posted on 2019-11-19 22:43  fox_charon  阅读(735)  评论(0编辑  收藏  举报

导航