react实战 : react 与 svg

怎甘沉沦 提交于 2019-12-05 16:37:24

有一个需求是这样的。

一个组件里若干个区块。区块数量不定。

区块里面是一个波浪效果组件,而这个一般用 SVG 做。

所以就变成了在 react 中使用 SVG 的问题。

 

首先是波浪效果需要的样式。

.p{
  font-size: 12px;
  line-height: 2;
  text-align: center;
  margin:0;
  width: 52px;
  color: #fff;
}

.irrigate_svg {
  height: 52px;
  width: 52px;
}
.masked {
  -webkit-mask: url(#myMask);
  mask: url(#myMask);
}
.irrigate_wrap {
  transform: translateY(112px);
}
.irrigate_svg {
  overflow: hidden;
}
.irrigate_rate {
  animation-name:wavingleft, wavingUp;
  animation-duration:6s, 6s;
  animation-timing-function:linear, linear;
  animation-iteration-count:infinite, 1;
}
@keyframes wavingleft {
  0% {
    transform: translateX(-239px);
  }
  50% {
    transform: translateX(0px);
  }
  100% {
    transform: translateX(-239px);
  }
}
@keyframes wavingright {
  0% {
    transform: translateX(0px);
  }
  50% {
    transform: translateX(-239px);
  }
  100% {
    transform: translateX(0px);
  }
}
@keyframes wavingUp{
  0% {
    transform: translateX(-239px) translateY(100px);
  }
  50% {
    transform: translateX(0px);
  }
  100% {
    transform: translateX(-239px) translateY(0px);
  }
}

 

引入样式,以及组件文件的结构。

import React from 'react'
import Styles from './waveContainer.less'

class Wave extends React.Component {}

class WaveContainer extends React.Component {}

export default WaveContainer

一个组件文件里可能有很多层组件,只需要输出最外面的一层。

 

SVG 组件。

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

  render(){
    const item = this.props.data

    const getNumberPosition = (number) => {
      let style
      const s = {
        s1:"matrix(1 0 0 1 96.44 150)",
        s2:"matrix(1 0 0 1 66.44 150)",
        s3:"matrix(1 0 0 1 46.44 150)",
      }

      switch (parseInt(number).toString().length) {
        case 0:
          style = s.s2
          break;
        case 1:
          style = s.s1
          break;
        case 2:
          style = s.s2
          break;
        case 3:
          style = s.s3
          break;
        default: 
          style = s.s2
      } 
      return style
    }

    const getColor = (item) => {
      return item.color
    }

    return (
      <div >
        <div className={Styles.irrigate_svg}>
          <svg version="1.1" id="图层_5" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 244.2 244.2" style={{ enableBackground:"new 0 0 244.2 244.2" }} >
            <defs>
              <mask id="myMask">
                <circle style={{ fill:"#fff",stroke:"#fff","strokeMiterlimit":"10" }} cx="122.1" cy="122.1" r="122.1"/>
              </mask>
            </defs>
            <g className={Styles.masked}>
              <g className={Styles.irrigate_wrap}>
                {/* <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="1120.8899" y1="262.1278" x2="1120.8899" y2="1.81" gradientTransform="matrix(-1 0 0 -1 1430.8899 246)">
                  <stop  offset="0" style={{ stopColor:getColor(item),"stopOpacity":"0.8" }}/>
                  <stop  offset="1" style={{ stopColor:getColor(item),"stopOpacity":"0.7"}}/>
                </linearGradient> */}
                <path className={Styles.irrigate_rate} style={{ fill:getColor(item) }} d="M0-3.8c0,0,44.7-14.3,77-12.1c32.9,2.3,95.6,33.3,128.3,31.1c38.9-2.6,116.7-33.7,153-29.7
                  c22.9,2.5,73,20.4,95.7,24.4c30.9,5.5,64.2,8.4,90.3,6.8C567.8,15.2,620-3.8,620-3.8v248H0V-3.8z"/>
              </g>
            </g>
            <g>
              <g id="图层_5-2">
                <circle style={{ fill:"none",stroke:"#25437C",strokeWidth:"1",strokeMiterlimit:"1" }} cx="122.1" cy="122.1" r="122.1"/>
                <text transform={getNumberPosition(item.data)} style={{ fill:"#FFF", fontSize:"100px" }}> {item.data} </text>
                  <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="0" y1="123.91" x2="244.18" y2="123.91" gradientTransform="matrix(1 0 0 -1 0 246)">
                    <stop  offset="0" style={{ stopColor:"rgb(55,107,112)" }}/>
                    <stop  offset="1" style={{ stopColor:"rgb(55,107,112)" }}/>
                  </linearGradient>
                <circle style={{ fill:"none",stroke:"url(#SVGID_3_)",strokeWidth:"1",strokeLinecap:"round",strokeMiterlimit:"1" }} cx="122.1" cy="122.1" r="122.1"/>
              </g>
            </g>
          </svg>
        </div>
        <p className={Styles.p}> {item.name} </p>
      </div>
    );
  }
}

 

SVG原本怎么写,JSX就怎么写。

但是遇到了一个问题。

linearGradient, 这个用来做渐变的标签,直接使用没有问题,但如果循环输出的时候把需要的值赋值进去,就会发现所有 SVG 组件的颜色都和第一个一样了。而用开发者工具查看的时候,颜色确实是赋值进去了。不知道是怎么回事。
 
然后是容器组件。
class WaveContainer extends React.Component {
  constructor(props){
    super(props)
    this.state = {
    }
  }

  render(){
    const baseFlex = {
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center'
    }
    const theStyle = {
      main:{
        ...baseFlex,
        width:'100%',
        height:'100%',
        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 dataBar = (() => {
      if (this.props.curcity && this.props.curcity === 'all') {
        return {
          data:{
            sData:[
              { name: 'a', data: 55, color:'rgb(79,239,223)' },
              { name: 'a', data: 5, color:'rgb(79,239,223)'},
              { name: 'a', data: 36, color:'rgb(79,239,223)'},
              { name: 'a', data: 476, color:'rgb(87,207,30)'},
              { name: 'a', data: 226, color:'rgb(79,239,223)'},
              { name: 'a', data: 273, color:'rgb(251,211,36)'}
            ]
          }
        }
      } else {
        return {
          data:{
            sData:[
              { name: 'a', data: 124, color:'rgb(79,239,223)' },
              { name: 'a', data: 253, color:'rgb(79,239,223)'},
              { name: 'a', data: 321, color:'rgb(79,239,223)'},
              { name: 'a', data: 156, color:'rgb(87,207,30)'},
              { name: 'a', data: 2, color:'rgb(79,239,223)'},
              { name: 'a', data: 77, color:'rgb(251,211,36)'}
            ]
          }
        }
      }
    })()

    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>
    );
  }
}

 

以上。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!